Refine desktop setup and remove bundled app center apps

This commit is contained in:
inman
2026-06-04 09:58:58 +08:00
parent 6153579b90
commit 84128dbe23
73 changed files with 3888 additions and 2024 deletions

View File

@@ -27,6 +27,33 @@ const mocks = vi.hoisted(() => ({
vi.mock('@electron/services/providers/provider-store', () => ({
getProviderAccount: mocks.getProviderAccount,
listProviderAccounts: mocks.listProviderAccounts,
providerAccountToConfig: (account: {
id: string;
vendorId: ProviderConfig['type'];
label: string;
baseUrl?: string;
apiProtocol?: ProviderConfig['apiProtocol'];
headers?: Record<string, string>;
model?: string;
fallbackModels?: string[];
fallbackAccountIds?: string[];
enabled: boolean;
createdAt: string;
updatedAt: string;
}): ProviderConfig => ({
id: account.id,
name: account.label,
type: account.vendorId,
baseUrl: account.baseUrl,
apiProtocol: account.apiProtocol,
headers: account.headers,
model: account.model,
fallbackModels: account.fallbackModels,
fallbackProviderIds: account.fallbackAccountIds,
enabled: account.enabled,
createdAt: account.createdAt,
updatedAt: account.updatedAt,
}),
}));
vi.mock('@electron/services/secrets/secret-store', () => ({
@@ -126,12 +153,12 @@ describe('provider-runtime-sync refresh strategy', () => {
mocks.listAgentsSnapshot.mockResolvedValue({ agents: [] });
});
it('uses debouncedReload after saving provider config', async () => {
it('uses debouncedRestart after saving provider config', async () => {
const gateway = createGateway('running');
await syncSavedProviderToRuntime(createProvider(), undefined, gateway as GatewayManager);
expect(gateway.debouncedReload).toHaveBeenCalledTimes(1);
expect(gateway.debouncedRestart).not.toHaveBeenCalled();
expect(gateway.debouncedRestart).toHaveBeenCalledTimes(1);
expect(gateway.debouncedReload).not.toHaveBeenCalled();
});
it('uses debouncedRestart after deleting provider config', async () => {
@@ -170,12 +197,90 @@ describe('provider-runtime-sync refresh strategy', () => {
expect(mocks.removeProviderFromOpenClaw).not.toHaveBeenCalled();
});
it('uses debouncedReload after switching default provider when gateway is running', async () => {
it('uses debouncedRestart after switching default provider when gateway is running', async () => {
const gateway = createGateway('running');
await syncDefaultProviderToRuntime('moonshot', gateway as GatewayManager);
expect(gateway.debouncedReload).toHaveBeenCalledTimes(1);
expect(gateway.debouncedRestart).not.toHaveBeenCalled();
expect(gateway.debouncedRestart).toHaveBeenCalledTimes(1);
expect(gateway.debouncedReload).not.toHaveBeenCalled();
});
it('syncs DeepSeek account defaults to the runtime model provider', async () => {
mocks.getProvider.mockResolvedValue(null);
mocks.getProviderAccount.mockResolvedValue({
id: 'deepseek-a1e23f39',
vendorId: 'deepseek',
label: 'DeepSeek',
authMode: 'api_key',
baseUrl: 'https://api.deepseek.com/v1',
model: 'deepseek-v4-pro',
enabled: true,
isDefault: true,
createdAt: '2026-06-03T00:00:00.000Z',
updatedAt: '2026-06-03T00:00:00.000Z',
});
mocks.getApiKey.mockResolvedValue('sk-deepseek');
mocks.getProviderConfig.mockImplementation((type: string) => {
if (type === 'deepseek') {
return {
api: 'openai-completions',
baseUrl: 'https://api.deepseek.com/v1',
apiKeyEnv: 'DEEPSEEK_API_KEY',
};
}
return {
api: 'openai-completions',
baseUrl: 'https://api.moonshot.cn/v1',
apiKeyEnv: 'MOONSHOT_API_KEY',
};
});
const gateway = createGateway('running');
await syncDefaultProviderToRuntime('deepseek-a1e23f39', gateway as GatewayManager);
expect(mocks.setOpenClawDefaultModelWithOverride).toHaveBeenCalledWith(
'deepseek',
'deepseek/deepseek-v4-pro',
expect.objectContaining({
baseUrl: 'https://api.deepseek.com/v1',
api: 'openai-completions',
apiKeyEnv: 'DEEPSEEK_API_KEY',
}),
[],
);
expect(mocks.saveProviderKeyToOpenClaw).toHaveBeenCalledWith('deepseek', 'sk-deepseek');
expect(gateway.debouncedRestart).toHaveBeenCalledTimes(1);
});
it('syncs default provider accounts even when no legacy provider entry exists', async () => {
mocks.getProvider.mockResolvedValue(null);
mocks.getProviderAccount.mockResolvedValue({
id: 'tenant1234',
vendorId: 'custom',
label: 'Tenant Model',
authMode: 'api_key',
baseUrl: 'https://llm.example.test/v1',
apiProtocol: 'openai-completions',
model: 'tenant-model',
enabled: true,
isDefault: true,
createdAt: '2026-06-03T00:00:00.000Z',
updatedAt: '2026-06-03T00:00:00.000Z',
});
mocks.getApiKey.mockResolvedValue('sk-tenant');
await syncDefaultProviderToRuntime('tenant1234');
expect(mocks.setOpenClawDefaultModelWithOverride).toHaveBeenCalledWith(
'custom-tenant12',
'custom-tenant12/tenant-model',
expect.objectContaining({
baseUrl: 'https://llm.example.test/v1',
api: 'openai-completions',
}),
[],
);
expect(mocks.saveProviderKeyToOpenClaw).toHaveBeenCalledWith('custom-tenant12', 'sk-tenant');
});
it('skips refresh after switching default provider when gateway is stopped', async () => {
@@ -281,7 +386,8 @@ describe('provider-runtime-sync refresh strategy', () => {
api: 'openai-completions',
}),
);
expect(gateway.debouncedReload).toHaveBeenCalledTimes(1);
expect(gateway.debouncedRestart).toHaveBeenCalledTimes(1);
expect(gateway.debouncedReload).not.toHaveBeenCalled();
});
it('syncs Ollama as default provider with correct baseUrl and api protocol', async () => {
@@ -339,7 +445,8 @@ describe('provider-runtime-sync refresh strategy', () => {
);
// Should NOT call the non-override path
expect(mocks.setOpenClawDefaultModel).not.toHaveBeenCalled();
expect(gateway.debouncedReload).toHaveBeenCalledTimes(1);
expect(gateway.debouncedRestart).toHaveBeenCalledTimes(1);
expect(gateway.debouncedReload).not.toHaveBeenCalled();
});
it('removes Ollama provider from runtime on delete', async () => {