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
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user