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
@@ -1,15 +1,5 @@
|
||||
import type { IncomingMessage, ServerResponse } from 'http';
|
||||
import {
|
||||
deleteApiKey,
|
||||
deleteProvider,
|
||||
getAllProvidersWithKeyInfo,
|
||||
getApiKey,
|
||||
getDefaultProvider,
|
||||
getProvider,
|
||||
hasApiKey,
|
||||
saveProvider,
|
||||
setDefaultProvider,
|
||||
storeApiKey,
|
||||
type ProviderConfig,
|
||||
} from '../../utils/secure-storage';
|
||||
import {
|
||||
@@ -135,19 +125,19 @@ export async function handleProviderRoutes(
|
||||
}
|
||||
|
||||
if (url.pathname === '/api/providers' && req.method === 'GET') {
|
||||
sendJson(res, 200, await getAllProvidersWithKeyInfo());
|
||||
sendJson(res, 200, await providerService.listLegacyProvidersWithKeyInfo());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (url.pathname === '/api/providers/default' && req.method === 'GET') {
|
||||
sendJson(res, 200, { providerId: await getDefaultProvider() ?? null });
|
||||
sendJson(res, 200, { providerId: await providerService.getDefaultLegacyProvider() ?? null });
|
||||
return true;
|
||||
}
|
||||
|
||||
if (url.pathname === '/api/providers/default' && req.method === 'PUT') {
|
||||
try {
|
||||
const body = await parseJsonBody<{ providerId: string }>(req);
|
||||
await setDefaultProvider(body.providerId);
|
||||
await providerService.setDefaultLegacyProvider(body.providerId);
|
||||
await syncDefaultProviderToRuntime(body.providerId, ctx.gatewayManager);
|
||||
sendJson(res, 200, { success: true });
|
||||
} catch (error) {
|
||||
@@ -159,7 +149,7 @@ export async function handleProviderRoutes(
|
||||
if (url.pathname === '/api/providers/validate' && req.method === 'POST') {
|
||||
try {
|
||||
const body = await parseJsonBody<{ providerId: string; apiKey: string; options?: { baseUrl?: string } }>(req);
|
||||
const provider = await getProvider(body.providerId);
|
||||
const provider = await providerService.getLegacyProvider(body.providerId);
|
||||
const providerType = provider?.type || body.providerId;
|
||||
const registryBaseUrl = getProviderConfig(providerType)?.baseUrl;
|
||||
const resolvedBaseUrl = body.options?.baseUrl || provider?.baseUrl || registryBaseUrl;
|
||||
@@ -211,11 +201,11 @@ export async function handleProviderRoutes(
|
||||
try {
|
||||
const body = await parseJsonBody<{ config: ProviderConfig; apiKey?: string }>(req);
|
||||
const config = body.config;
|
||||
await saveProvider(config);
|
||||
await providerService.saveLegacyProvider(config);
|
||||
if (body.apiKey !== undefined) {
|
||||
const trimmedKey = body.apiKey.trim();
|
||||
if (trimmedKey) {
|
||||
await storeApiKey(config.id, trimmedKey);
|
||||
await providerService.setLegacyProviderApiKey(config.id, trimmedKey);
|
||||
await syncProviderApiKeyToRuntime(config.type, config.id, trimmedKey);
|
||||
}
|
||||
}
|
||||
@@ -231,15 +221,15 @@ export async function handleProviderRoutes(
|
||||
const providerId = decodeURIComponent(url.pathname.slice('/api/providers/'.length));
|
||||
if (providerId.endsWith('/api-key')) {
|
||||
const actualId = providerId.slice(0, -('/api-key'.length));
|
||||
sendJson(res, 200, { apiKey: await getApiKey(actualId) });
|
||||
sendJson(res, 200, { apiKey: await providerService.getLegacyProviderApiKey(actualId) });
|
||||
return true;
|
||||
}
|
||||
if (providerId.endsWith('/has-api-key')) {
|
||||
const actualId = providerId.slice(0, -('/has-api-key'.length));
|
||||
sendJson(res, 200, { hasKey: await hasApiKey(actualId) });
|
||||
sendJson(res, 200, { hasKey: await providerService.hasLegacyProviderApiKey(actualId) });
|
||||
return true;
|
||||
}
|
||||
sendJson(res, 200, await getProvider(providerId));
|
||||
sendJson(res, 200, await providerService.getLegacyProvider(providerId));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -247,20 +237,20 @@ export async function handleProviderRoutes(
|
||||
const providerId = decodeURIComponent(url.pathname.slice('/api/providers/'.length));
|
||||
try {
|
||||
const body = await parseJsonBody<{ updates: Partial<ProviderConfig>; apiKey?: string }>(req);
|
||||
const existing = await getProvider(providerId);
|
||||
const existing = await providerService.getLegacyProvider(providerId);
|
||||
if (!existing) {
|
||||
sendJson(res, 404, { success: false, error: 'Provider not found' });
|
||||
return true;
|
||||
}
|
||||
const nextConfig: ProviderConfig = { ...existing, ...body.updates, updatedAt: new Date().toISOString() };
|
||||
await saveProvider(nextConfig);
|
||||
await providerService.saveLegacyProvider(nextConfig);
|
||||
if (body.apiKey !== undefined) {
|
||||
const trimmedKey = body.apiKey.trim();
|
||||
if (trimmedKey) {
|
||||
await storeApiKey(providerId, trimmedKey);
|
||||
await providerService.setLegacyProviderApiKey(providerId, trimmedKey);
|
||||
await syncProviderApiKeyToRuntime(nextConfig.type, providerId, trimmedKey);
|
||||
} else {
|
||||
await deleteApiKey(providerId);
|
||||
await providerService.deleteLegacyProviderApiKey(providerId);
|
||||
await syncDeletedProviderApiKeyToRuntime(existing, providerId);
|
||||
}
|
||||
}
|
||||
@@ -275,14 +265,14 @@ export async function handleProviderRoutes(
|
||||
if (url.pathname.startsWith('/api/providers/') && req.method === 'DELETE') {
|
||||
const providerId = decodeURIComponent(url.pathname.slice('/api/providers/'.length));
|
||||
try {
|
||||
const existing = await getProvider(providerId);
|
||||
const existing = await providerService.getLegacyProvider(providerId);
|
||||
if (url.searchParams.get('apiKeyOnly') === '1') {
|
||||
await deleteApiKey(providerId);
|
||||
await providerService.deleteLegacyProviderApiKey(providerId);
|
||||
await syncDeletedProviderApiKeyToRuntime(existing, providerId);
|
||||
sendJson(res, 200, { success: true });
|
||||
return true;
|
||||
}
|
||||
await deleteProvider(providerId);
|
||||
await providerService.deleteLegacyProvider(providerId);
|
||||
await syncDeletedProviderToRuntime(existing, providerId, ctx.gatewayManager);
|
||||
sendJson(res, 200, { success: true });
|
||||
} catch (error) {
|
||||
|
||||
@@ -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 }] : [],
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -22,6 +22,7 @@ const electronAPI = {
|
||||
'gateway:restart',
|
||||
'gateway:rpc',
|
||||
'gateway:httpProxy',
|
||||
'hostapi:fetch',
|
||||
'gateway:health',
|
||||
'gateway:getControlUiUrl',
|
||||
// OpenClaw
|
||||
|
||||
@@ -18,6 +18,12 @@ import { logger } from '../../utils/logger';
|
||||
const GOOGLE_OAUTH_RUNTIME_PROVIDER = 'google-gemini-cli';
|
||||
const GOOGLE_OAUTH_DEFAULT_MODEL_REF = `${GOOGLE_OAUTH_RUNTIME_PROVIDER}/gemini-3-pro-preview`;
|
||||
|
||||
type RuntimeProviderSyncContext = {
|
||||
runtimeProviderKey: string;
|
||||
meta: ReturnType<typeof getProviderConfig>;
|
||||
api: string;
|
||||
};
|
||||
|
||||
export function getOpenClawProviderKey(type: string, providerId: string): string {
|
||||
if (type === 'custom' || type === 'ollama') {
|
||||
const suffix = providerId.replace(/-/g, '').slice(0, 8);
|
||||
@@ -172,63 +178,119 @@ export async function syncAllProviderAuthToRuntime(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function syncSavedProviderToRuntime(
|
||||
async function syncProviderSecretToRuntime(
|
||||
config: ProviderConfig,
|
||||
runtimeProviderKey: string,
|
||||
apiKey: string | undefined,
|
||||
gatewayManager?: GatewayManager,
|
||||
): Promise<void> {
|
||||
const ock = await resolveRuntimeProviderKey(config);
|
||||
const secret = await getProviderSecret(config.id);
|
||||
|
||||
if (apiKey !== undefined) {
|
||||
const trimmedKey = apiKey.trim();
|
||||
if (trimmedKey) {
|
||||
await saveProviderKeyToOpenClaw(ock, trimmedKey);
|
||||
await saveProviderKeyToOpenClaw(runtimeProviderKey, trimmedKey);
|
||||
}
|
||||
} else if (secret?.type === 'api_key') {
|
||||
await saveProviderKeyToOpenClaw(ock, secret.apiKey);
|
||||
} else if (secret?.type === 'oauth') {
|
||||
await saveOAuthTokenToOpenClaw(ock, {
|
||||
return;
|
||||
}
|
||||
|
||||
if (secret?.type === 'api_key') {
|
||||
await saveProviderKeyToOpenClaw(runtimeProviderKey, secret.apiKey);
|
||||
return;
|
||||
}
|
||||
|
||||
if (secret?.type === 'oauth') {
|
||||
await saveOAuthTokenToOpenClaw(runtimeProviderKey, {
|
||||
access: secret.accessToken,
|
||||
refresh: secret.refreshToken,
|
||||
expires: secret.expiresAt,
|
||||
email: secret.email,
|
||||
projectId: secret.subject,
|
||||
});
|
||||
} else if (secret?.type === 'local' && secret.apiKey) {
|
||||
await saveProviderKeyToOpenClaw(ock, secret.apiKey);
|
||||
}
|
||||
|
||||
const meta = getProviderConfig(config.type);
|
||||
const api = config.type === 'custom' || config.type === 'ollama' ? 'openai-completions' : meta?.api;
|
||||
|
||||
if (!api) {
|
||||
return;
|
||||
}
|
||||
|
||||
await syncProviderConfigToOpenClaw(ock, config.model, {
|
||||
baseUrl: config.baseUrl || meta?.baseUrl,
|
||||
api,
|
||||
apiKeyEnv: meta?.apiKeyEnv,
|
||||
headers: meta?.headers,
|
||||
});
|
||||
if (secret?.type === 'local' && secret.apiKey) {
|
||||
await saveProviderKeyToOpenClaw(runtimeProviderKey, secret.apiKey);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.type === 'custom' || config.type === 'ollama') {
|
||||
const resolvedKey = apiKey !== undefined ? (apiKey.trim() || null) : await getApiKey(config.id);
|
||||
if (resolvedKey && config.baseUrl) {
|
||||
const modelId = config.model;
|
||||
await updateAgentModelProvider(ock, {
|
||||
baseUrl: config.baseUrl,
|
||||
api: 'openai-completions',
|
||||
models: modelId ? [{ id: modelId, name: modelId }] : [],
|
||||
apiKey: resolvedKey,
|
||||
});
|
||||
}
|
||||
async function resolveRuntimeSyncContext(config: ProviderConfig): Promise<RuntimeProviderSyncContext | null> {
|
||||
const runtimeProviderKey = await resolveRuntimeProviderKey(config);
|
||||
const meta = getProviderConfig(config.type);
|
||||
const api = config.type === 'custom' || config.type === 'ollama' ? 'openai-completions' : meta?.api;
|
||||
if (!api) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
runtimeProviderKey,
|
||||
meta,
|
||||
api,
|
||||
};
|
||||
}
|
||||
|
||||
async function syncRuntimeProviderConfig(
|
||||
config: ProviderConfig,
|
||||
context: RuntimeProviderSyncContext,
|
||||
): Promise<void> {
|
||||
await syncProviderConfigToOpenClaw(context.runtimeProviderKey, config.model, {
|
||||
baseUrl: config.baseUrl || context.meta?.baseUrl,
|
||||
api: context.api,
|
||||
apiKeyEnv: context.meta?.apiKeyEnv,
|
||||
headers: context.meta?.headers,
|
||||
});
|
||||
}
|
||||
|
||||
async function syncCustomProviderAgentModel(
|
||||
config: ProviderConfig,
|
||||
runtimeProviderKey: string,
|
||||
apiKey: string | undefined,
|
||||
): Promise<void> {
|
||||
if (config.type !== 'custom' && config.type !== 'ollama') {
|
||||
return;
|
||||
}
|
||||
|
||||
const resolvedKey = apiKey !== undefined ? (apiKey.trim() || null) : await getApiKey(config.id);
|
||||
if (!resolvedKey || !config.baseUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const modelId = config.model;
|
||||
await updateAgentModelProvider(runtimeProviderKey, {
|
||||
baseUrl: config.baseUrl,
|
||||
api: 'openai-completions',
|
||||
models: modelId ? [{ id: modelId, name: modelId }] : [],
|
||||
apiKey: resolvedKey,
|
||||
});
|
||||
}
|
||||
|
||||
async function syncProviderToRuntime(
|
||||
config: ProviderConfig,
|
||||
apiKey: string | undefined,
|
||||
): Promise<RuntimeProviderSyncContext | null> {
|
||||
const context = await resolveRuntimeSyncContext(config);
|
||||
if (!context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
await syncProviderSecretToRuntime(config, context.runtimeProviderKey, apiKey);
|
||||
await syncRuntimeProviderConfig(config, context);
|
||||
await syncCustomProviderAgentModel(config, context.runtimeProviderKey, apiKey);
|
||||
return context;
|
||||
}
|
||||
|
||||
export async function syncSavedProviderToRuntime(
|
||||
config: ProviderConfig,
|
||||
apiKey: string | undefined,
|
||||
gatewayManager?: GatewayManager,
|
||||
): Promise<void> {
|
||||
const context = await syncProviderToRuntime(config, apiKey);
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
scheduleGatewayRestart(
|
||||
gatewayManager,
|
||||
`Scheduling Gateway restart after saving provider "${ock}" config`,
|
||||
`Scheduling Gateway restart after saving provider "${context.runtimeProviderKey}" config`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -237,54 +299,13 @@ export async function syncUpdatedProviderToRuntime(
|
||||
apiKey: string | undefined,
|
||||
gatewayManager?: GatewayManager,
|
||||
): Promise<void> {
|
||||
const ock = await resolveRuntimeProviderKey(config);
|
||||
const fallbackModels = await getProviderFallbackModelRefs(config);
|
||||
const meta = getProviderConfig(config.type);
|
||||
const api = config.type === 'custom' || config.type === 'ollama' ? 'openai-completions' : meta?.api;
|
||||
const secret = await getProviderSecret(config.id);
|
||||
|
||||
if (!api) {
|
||||
const context = await syncProviderToRuntime(config, apiKey);
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (apiKey !== undefined) {
|
||||
const trimmedKey = apiKey.trim();
|
||||
if (trimmedKey) {
|
||||
await saveProviderKeyToOpenClaw(ock, trimmedKey);
|
||||
}
|
||||
} else if (secret?.type === 'api_key') {
|
||||
await saveProviderKeyToOpenClaw(ock, secret.apiKey);
|
||||
} else if (secret?.type === 'oauth') {
|
||||
await saveOAuthTokenToOpenClaw(ock, {
|
||||
access: secret.accessToken,
|
||||
refresh: secret.refreshToken,
|
||||
expires: secret.expiresAt,
|
||||
email: secret.email,
|
||||
projectId: secret.subject,
|
||||
});
|
||||
} else if (secret?.type === 'local' && secret.apiKey) {
|
||||
await saveProviderKeyToOpenClaw(ock, secret.apiKey);
|
||||
}
|
||||
|
||||
await syncProviderConfigToOpenClaw(ock, config.model, {
|
||||
baseUrl: config.baseUrl || meta?.baseUrl,
|
||||
api,
|
||||
apiKeyEnv: meta?.apiKeyEnv,
|
||||
headers: meta?.headers,
|
||||
});
|
||||
|
||||
if (config.type === 'custom' || config.type === 'ollama') {
|
||||
const resolvedKey = apiKey !== undefined ? (apiKey.trim() || null) : await getApiKey(config.id);
|
||||
if (resolvedKey && config.baseUrl) {
|
||||
const modelId = config.model;
|
||||
await updateAgentModelProvider(ock, {
|
||||
baseUrl: config.baseUrl,
|
||||
api: 'openai-completions',
|
||||
models: modelId ? [{ id: modelId, name: modelId }] : [],
|
||||
apiKey: resolvedKey,
|
||||
});
|
||||
}
|
||||
}
|
||||
const ock = context.runtimeProviderKey;
|
||||
const fallbackModels = await getProviderFallbackModelRefs(config);
|
||||
|
||||
const defaultProviderId = await getDefaultProvider();
|
||||
if (defaultProviderId === config.id) {
|
||||
|
||||
@@ -20,11 +20,7 @@ import {
|
||||
import {
|
||||
deleteApiKey,
|
||||
deleteProvider,
|
||||
getAllProviders,
|
||||
getAllProvidersWithKeyInfo,
|
||||
getApiKey,
|
||||
getDefaultProvider,
|
||||
getProvider,
|
||||
hasApiKey,
|
||||
saveProvider,
|
||||
setDefaultProvider,
|
||||
@@ -32,6 +28,14 @@ import {
|
||||
} from '../../utils/secure-storage';
|
||||
import type { ProviderWithKeyInfo } from '../../shared/providers/types';
|
||||
|
||||
function maskApiKey(apiKey: string | null): string | null {
|
||||
if (!apiKey) return null;
|
||||
if (apiKey.length > 12) {
|
||||
return `${apiKey.substring(0, 4)}${'*'.repeat(apiKey.length - 8)}${apiKey.substring(apiKey.length - 4)}`;
|
||||
}
|
||||
return '*'.repeat(apiKey.length);
|
||||
}
|
||||
|
||||
export class ProviderService {
|
||||
async listVendors(): Promise<ProviderDefinition[]> {
|
||||
return PROVIDER_DEFINITIONS;
|
||||
@@ -49,7 +53,7 @@ export class ProviderService {
|
||||
|
||||
async getDefaultAccountId(): Promise<string | undefined> {
|
||||
await ensureProviderStoreMigrated();
|
||||
return (await getDefaultProvider()) ?? getDefaultProviderAccountId();
|
||||
return getDefaultProviderAccountId();
|
||||
}
|
||||
|
||||
async createAccount(account: ProviderAccount, apiKey?: string): Promise<ProviderAccount> {
|
||||
@@ -107,31 +111,54 @@ export class ProviderService {
|
||||
}
|
||||
|
||||
async listLegacyProviders(): Promise<ProviderConfig[]> {
|
||||
return getAllProviders();
|
||||
await ensureProviderStoreMigrated();
|
||||
const accounts = await listProviderAccounts();
|
||||
return accounts.map(providerAccountToConfig);
|
||||
}
|
||||
|
||||
async listLegacyProvidersWithKeyInfo(): Promise<ProviderWithKeyInfo[]> {
|
||||
return getAllProvidersWithKeyInfo();
|
||||
const providers = await this.listLegacyProviders();
|
||||
const results: ProviderWithKeyInfo[] = [];
|
||||
for (const provider of providers) {
|
||||
const apiKey = await getApiKey(provider.id);
|
||||
results.push({
|
||||
...provider,
|
||||
hasKey: !!apiKey,
|
||||
keyMasked: maskApiKey(apiKey),
|
||||
});
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
async getLegacyProvider(providerId: string): Promise<ProviderConfig | null> {
|
||||
return getProvider(providerId);
|
||||
await ensureProviderStoreMigrated();
|
||||
const account = await getProviderAccount(providerId);
|
||||
return account ? providerAccountToConfig(account) : null;
|
||||
}
|
||||
|
||||
async saveLegacyProvider(config: ProviderConfig): Promise<void> {
|
||||
await saveProvider(config);
|
||||
await ensureProviderStoreMigrated();
|
||||
const account = providerConfigToAccount(config);
|
||||
const existing = await getProviderAccount(config.id);
|
||||
if (existing) {
|
||||
await this.updateAccount(config.id, account);
|
||||
return;
|
||||
}
|
||||
await this.createAccount(account);
|
||||
}
|
||||
|
||||
async deleteLegacyProvider(providerId: string): Promise<boolean> {
|
||||
return deleteProvider(providerId);
|
||||
await ensureProviderStoreMigrated();
|
||||
await this.deleteAccount(providerId);
|
||||
return true;
|
||||
}
|
||||
|
||||
async setDefaultLegacyProvider(providerId: string): Promise<void> {
|
||||
await setDefaultProvider(providerId);
|
||||
await this.setDefaultAccount(providerId);
|
||||
}
|
||||
|
||||
async getDefaultLegacyProvider(): Promise<string | undefined> {
|
||||
return getDefaultProvider();
|
||||
return this.getDefaultAccountId();
|
||||
}
|
||||
|
||||
async setLegacyProviderApiKey(providerId: string, apiKey: string): Promise<boolean> {
|
||||
|
||||
@@ -386,21 +386,14 @@ export async function setOpenClawDefaultModel(
|
||||
const config = await readOpenClawJson();
|
||||
ensureMoonshotKimiWebSearchCnBaseUrl(config, provider);
|
||||
|
||||
const rawModel = modelOverride || getProviderDefaultModel(provider);
|
||||
const model = rawModel
|
||||
? (rawModel.startsWith(`${provider}/`) ? rawModel : `${provider}/${rawModel}`)
|
||||
: undefined;
|
||||
const model = normalizeModelRef(provider, modelOverride);
|
||||
if (!model) {
|
||||
console.warn(`No default model mapping for provider "${provider}"`);
|
||||
return;
|
||||
}
|
||||
|
||||
const modelId = model.startsWith(`${provider}/`)
|
||||
? model.slice(provider.length + 1)
|
||||
: model;
|
||||
const fallbackModelIds = fallbackModels
|
||||
.filter((fallback) => fallback.startsWith(`${provider}/`))
|
||||
.map((fallback) => fallback.slice(provider.length + 1));
|
||||
const modelId = extractModelId(provider, model);
|
||||
const fallbackModelIds = extractFallbackModelIds(provider, fallbackModels);
|
||||
|
||||
// Set the default model for the agents
|
||||
const agents = (config.agents || {}) as Record<string, unknown>;
|
||||
@@ -415,51 +408,16 @@ export async function setOpenClawDefaultModel(
|
||||
// Configure models.providers for providers that need explicit registration.
|
||||
const providerCfg = getProviderConfig(provider);
|
||||
if (providerCfg) {
|
||||
const models = (config.models || {}) as Record<string, unknown>;
|
||||
const providers = (models.providers || {}) as Record<string, unknown>;
|
||||
const removedLegacyMoonshot = removeLegacyMoonshotProviderEntry(provider, providers);
|
||||
|
||||
const existingProvider =
|
||||
providers[provider] && typeof providers[provider] === 'object'
|
||||
? (providers[provider] as Record<string, unknown>)
|
||||
: {};
|
||||
|
||||
const existingModels = Array.isArray(existingProvider.models)
|
||||
? (existingProvider.models as Array<Record<string, unknown>>)
|
||||
: [];
|
||||
const registryModels = (providerCfg.models ?? []).map((m) => ({ ...m })) as Array<Record<string, unknown>>;
|
||||
|
||||
const mergedModels = [...registryModels];
|
||||
for (const item of existingModels) {
|
||||
const id = typeof item?.id === 'string' ? item.id : '';
|
||||
if (id && !mergedModels.some((m) => m.id === id)) {
|
||||
mergedModels.push(item);
|
||||
}
|
||||
}
|
||||
for (const candidateModelId of [modelId, ...fallbackModelIds]) {
|
||||
if (candidateModelId && !mergedModels.some((m) => m.id === candidateModelId)) {
|
||||
mergedModels.push({ id: candidateModelId, name: candidateModelId });
|
||||
}
|
||||
}
|
||||
|
||||
const providerEntry: Record<string, unknown> = {
|
||||
...existingProvider,
|
||||
upsertOpenClawProviderEntry(config, provider, {
|
||||
baseUrl: providerCfg.baseUrl,
|
||||
api: providerCfg.api,
|
||||
apiKey: providerCfg.apiKeyEnv,
|
||||
models: mergedModels,
|
||||
};
|
||||
if (providerCfg.headers && Object.keys(providerCfg.headers).length > 0) {
|
||||
providerEntry.headers = providerCfg.headers;
|
||||
}
|
||||
providers[provider] = providerEntry;
|
||||
apiKeyEnv: providerCfg.apiKeyEnv,
|
||||
headers: providerCfg.headers,
|
||||
modelIds: [modelId, ...fallbackModelIds],
|
||||
includeRegistryModels: true,
|
||||
mergeExistingModels: true,
|
||||
});
|
||||
console.log(`Configured models.providers.${provider} with baseUrl=${providerCfg.baseUrl}, model=${modelId}`);
|
||||
if (removedLegacyMoonshot) {
|
||||
console.log('Removed legacy models.providers.moonshot alias entry');
|
||||
}
|
||||
|
||||
models.providers = providers;
|
||||
config.models = models;
|
||||
} else {
|
||||
// Built-in provider: remove any stale models.providers entry
|
||||
const models = (config.models || {}) as Record<string, unknown>;
|
||||
@@ -489,6 +447,99 @@ interface RuntimeProviderConfigOverride {
|
||||
authHeader?: boolean;
|
||||
}
|
||||
|
||||
type ProviderEntryBuildOptions = {
|
||||
baseUrl: string;
|
||||
api: string;
|
||||
apiKeyEnv?: string;
|
||||
headers?: Record<string, string>;
|
||||
authHeader?: boolean;
|
||||
modelIds?: string[];
|
||||
includeRegistryModels?: boolean;
|
||||
mergeExistingModels?: boolean;
|
||||
};
|
||||
|
||||
function normalizeModelRef(provider: string, modelOverride?: string): string | undefined {
|
||||
const rawModel = modelOverride || getProviderDefaultModel(provider);
|
||||
if (!rawModel) return undefined;
|
||||
return rawModel.startsWith(`${provider}/`) ? rawModel : `${provider}/${rawModel}`;
|
||||
}
|
||||
|
||||
function extractModelId(provider: string, modelRef: string): string {
|
||||
return modelRef.startsWith(`${provider}/`) ? modelRef.slice(provider.length + 1) : modelRef;
|
||||
}
|
||||
|
||||
function extractFallbackModelIds(provider: string, fallbackModels: string[]): string[] {
|
||||
return fallbackModels
|
||||
.filter((fallback) => fallback.startsWith(`${provider}/`))
|
||||
.map((fallback) => fallback.slice(provider.length + 1));
|
||||
}
|
||||
|
||||
function mergeProviderModels(
|
||||
...groups: Array<Array<Record<string, unknown>>>
|
||||
): Array<Record<string, unknown>> {
|
||||
const merged: Array<Record<string, unknown>> = [];
|
||||
const seen = new Set<string>();
|
||||
|
||||
for (const group of groups) {
|
||||
for (const item of group) {
|
||||
const id = typeof item?.id === 'string' ? item.id : '';
|
||||
if (!id || seen.has(id)) continue;
|
||||
seen.add(id);
|
||||
merged.push(item);
|
||||
}
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
function upsertOpenClawProviderEntry(
|
||||
config: Record<string, unknown>,
|
||||
provider: string,
|
||||
options: ProviderEntryBuildOptions,
|
||||
): void {
|
||||
const models = (config.models || {}) as Record<string, unknown>;
|
||||
const providers = (models.providers || {}) as Record<string, unknown>;
|
||||
const removedLegacyMoonshot = removeLegacyMoonshotProviderEntry(provider, providers);
|
||||
const existingProvider = (
|
||||
providers[provider] && typeof providers[provider] === 'object'
|
||||
? (providers[provider] as Record<string, unknown>)
|
||||
: {}
|
||||
);
|
||||
|
||||
const existingModels = options.mergeExistingModels && Array.isArray(existingProvider.models)
|
||||
? (existingProvider.models as Array<Record<string, unknown>>)
|
||||
: [];
|
||||
const registryModels = options.includeRegistryModels
|
||||
? ((getProviderConfig(provider)?.models ?? []).map((m) => ({ ...m })) as Array<Record<string, unknown>>)
|
||||
: [];
|
||||
const runtimeModels = (options.modelIds ?? []).map((id) => ({ id, name: id }));
|
||||
|
||||
const nextProvider: Record<string, unknown> = {
|
||||
...existingProvider,
|
||||
baseUrl: options.baseUrl,
|
||||
api: options.api,
|
||||
models: mergeProviderModels(registryModels, existingModels, runtimeModels),
|
||||
};
|
||||
if (options.apiKeyEnv) nextProvider.apiKey = options.apiKeyEnv;
|
||||
if (options.headers && Object.keys(options.headers).length > 0) {
|
||||
nextProvider.headers = options.headers;
|
||||
} else {
|
||||
delete nextProvider.headers;
|
||||
}
|
||||
if (options.authHeader !== undefined) {
|
||||
nextProvider.authHeader = options.authHeader;
|
||||
} else {
|
||||
delete nextProvider.authHeader;
|
||||
}
|
||||
|
||||
providers[provider] = nextProvider;
|
||||
models.providers = providers;
|
||||
config.models = models;
|
||||
|
||||
if (removedLegacyMoonshot) {
|
||||
console.log('Removed legacy models.providers.moonshot alias entry');
|
||||
}
|
||||
}
|
||||
|
||||
function removeLegacyMoonshotProviderEntry(
|
||||
_provider: string,
|
||||
_providers: Record<string, unknown>
|
||||
@@ -528,26 +579,13 @@ export async function syncProviderConfigToOpenClaw(
|
||||
ensureMoonshotKimiWebSearchCnBaseUrl(config, provider);
|
||||
|
||||
if (override.baseUrl && override.api) {
|
||||
const models = (config.models || {}) as Record<string, unknown>;
|
||||
const providers = (models.providers || {}) as Record<string, unknown>;
|
||||
removeLegacyMoonshotProviderEntry(provider, providers);
|
||||
|
||||
const nextModels: Array<Record<string, unknown>> = [];
|
||||
if (modelId) nextModels.push({ id: modelId, name: modelId });
|
||||
|
||||
const nextProvider: Record<string, unknown> = {
|
||||
upsertOpenClawProviderEntry(config, provider, {
|
||||
baseUrl: override.baseUrl,
|
||||
api: override.api,
|
||||
models: nextModels,
|
||||
};
|
||||
if (override.apiKeyEnv) nextProvider.apiKey = override.apiKeyEnv;
|
||||
if (override.headers && Object.keys(override.headers).length > 0) {
|
||||
nextProvider.headers = override.headers;
|
||||
}
|
||||
|
||||
providers[provider] = nextProvider;
|
||||
models.providers = providers;
|
||||
config.models = models;
|
||||
apiKeyEnv: override.apiKeyEnv,
|
||||
headers: override.headers,
|
||||
modelIds: modelId ? [modelId] : [],
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure extension is enabled for oauth providers to prevent gateway wiping config
|
||||
@@ -580,21 +618,14 @@ export async function setOpenClawDefaultModelWithOverride(
|
||||
const config = await readOpenClawJson();
|
||||
ensureMoonshotKimiWebSearchCnBaseUrl(config, provider);
|
||||
|
||||
const rawModel = modelOverride || getProviderDefaultModel(provider);
|
||||
const model = rawModel
|
||||
? (rawModel.startsWith(`${provider}/`) ? rawModel : `${provider}/${rawModel}`)
|
||||
: undefined;
|
||||
const model = normalizeModelRef(provider, modelOverride);
|
||||
if (!model) {
|
||||
console.warn(`No default model mapping for provider "${provider}"`);
|
||||
return;
|
||||
}
|
||||
|
||||
const modelId = model.startsWith(`${provider}/`)
|
||||
? model.slice(provider.length + 1)
|
||||
: model;
|
||||
const fallbackModelIds = fallbackModels
|
||||
.filter((fallback) => fallback.startsWith(`${provider}/`))
|
||||
.map((fallback) => fallback.slice(provider.length + 1));
|
||||
const modelId = extractModelId(provider, model);
|
||||
const fallbackModelIds = extractFallbackModelIds(provider, fallbackModels);
|
||||
|
||||
const agents = (config.agents || {}) as Record<string, unknown>;
|
||||
const defaults = (agents.defaults || {}) as Record<string, unknown>;
|
||||
@@ -606,33 +637,14 @@ export async function setOpenClawDefaultModelWithOverride(
|
||||
config.agents = agents;
|
||||
|
||||
if (override.baseUrl && override.api) {
|
||||
const models = (config.models || {}) as Record<string, unknown>;
|
||||
const providers = (models.providers || {}) as Record<string, unknown>;
|
||||
removeLegacyMoonshotProviderEntry(provider, providers);
|
||||
|
||||
const nextModels: Array<Record<string, unknown>> = [];
|
||||
for (const candidateModelId of [modelId, ...fallbackModelIds]) {
|
||||
if (candidateModelId && !nextModels.some((entry) => entry.id === candidateModelId)) {
|
||||
nextModels.push({ id: candidateModelId, name: candidateModelId });
|
||||
}
|
||||
}
|
||||
|
||||
const nextProvider: Record<string, unknown> = {
|
||||
upsertOpenClawProviderEntry(config, provider, {
|
||||
baseUrl: override.baseUrl,
|
||||
api: override.api,
|
||||
models: nextModels,
|
||||
};
|
||||
if (override.apiKeyEnv) nextProvider.apiKey = override.apiKeyEnv;
|
||||
if (override.headers && Object.keys(override.headers).length > 0) {
|
||||
nextProvider.headers = override.headers;
|
||||
}
|
||||
if (override.authHeader !== undefined) {
|
||||
nextProvider.authHeader = override.authHeader;
|
||||
}
|
||||
|
||||
providers[provider] = nextProvider;
|
||||
models.providers = providers;
|
||||
config.models = models;
|
||||
apiKeyEnv: override.apiKeyEnv,
|
||||
headers: override.headers,
|
||||
authHeader: override.authHeader,
|
||||
modelIds: [modelId, ...fallbackModelIds],
|
||||
});
|
||||
}
|
||||
|
||||
const gateway = (config.gateway || {}) as Record<string, unknown>;
|
||||
|
||||
@@ -36,7 +36,6 @@ export interface AppSettings {
|
||||
proxyHttpsServer: string;
|
||||
proxyAllServer: string;
|
||||
proxyBypassRules: string;
|
||||
gatewayTransportPreference: 'ws-first' | 'http-first' | 'ws-only' | 'http-only' | 'ipc-only';
|
||||
|
||||
// Update
|
||||
updateChannel: 'stable' | 'beta' | 'dev';
|
||||
@@ -74,7 +73,6 @@ const defaults: AppSettings = {
|
||||
proxyHttpsServer: '',
|
||||
proxyAllServer: '',
|
||||
proxyBypassRules: '<local>;localhost;127.0.0.1;::1',
|
||||
gatewayTransportPreference: 'ws-first',
|
||||
|
||||
// Update
|
||||
updateChannel: 'stable',
|
||||
|
||||
Reference in New Issue
Block a user