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

@@ -2,6 +2,11 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import {
YINIAN_MODEL_AUTH_PROFILE_ID,
YINIAN_MODEL_DEFAULT_BASE_URL,
YINIAN_MODEL_PROVIDER_KEY,
} from '../../shared/yinian-model';
const modelDiagnosticsMocks = vi.hoisted(() => ({
config: {} as Record<string, unknown>,
@@ -86,7 +91,7 @@ describe('Yinian model diagnostics', () => {
rmSync(modelDiagnosticsMocks.testOpenClawDir, { recursive: true, force: true });
});
it('repairs runtime model defaults and normalizes MiniMax auth profile aliases', async () => {
it('does not seed legacy runtime model defaults as the generic model API provider', async () => {
const {
buildYinianModelConfigDiagnostics,
ensureYinianModelRuntimeConfigured,
@@ -94,35 +99,241 @@ describe('Yinian model diagnostics', () => {
await ensureYinianModelRuntimeConfigured();
expect(modelDiagnosticsMocks.writeOpenClawConfig).toHaveBeenCalledWith(expect.objectContaining({
models: expect.objectContaining({
providers: expect.objectContaining({
minimax: expect.not.objectContaining({ timeoutSeconds: expect.anything() }),
}),
}),
agents: expect.objectContaining({
defaults: expect.objectContaining({
heartbeat: expect.objectContaining({ every: '0m' }),
}),
}),
}));
const config = modelDiagnosticsMocks.config as {
models: {
mode?: string;
pricing?: unknown;
providers: Record<string, { timeoutSeconds?: number }>;
};
agents: {
defaults: {
heartbeat?: { every?: string };
model: { primary?: string; fallbacks?: string[] };
};
};
};
expect(config.models.mode).toBe('merge');
expect(config.models.pricing).toBeUndefined();
expect(config.models.providers.minimax.timeoutSeconds).toBeUndefined();
expect(config.models.providers[YINIAN_MODEL_PROVIDER_KEY]).toBeUndefined();
expect(config.agents.defaults.model.primary).toBe('minimax/MiniMax-M2.7');
expect(config.agents.defaults.model.fallbacks).toEqual(['minimax/MiniMax-M2.5']);
expect(config.agents.defaults.heartbeat?.every).toBe('0m');
const authStore = JSON.parse(readFileSync(authProfilesPath(testHome), 'utf8')) as {
profiles: Record<string, { provider?: string; key?: string }>;
order?: Record<string, string[]>;
lastGood?: Record<string, string>;
};
expect(authStore.profiles['minimax:default']).toMatchObject({
provider: 'minimax',
key: 'secret',
});
expect(authStore.order?.minimax).toContain('minimax:default');
expect(authStore.lastGood?.minimax).toBe('minimax:default');
expect(authStore.profiles[YINIAN_MODEL_AUTH_PROFILE_ID]).toBeUndefined();
expect(authStore.order?.[YINIAN_MODEL_PROVIDER_KEY]).toBeUndefined();
expect(authStore.lastGood?.[YINIAN_MODEL_PROVIDER_KEY]).toBeUndefined();
const diagnostics = await buildYinianModelConfigDiagnostics();
expect(diagnostics.model.primary).toBe('minimax/MiniMax-M2.7');
expect(diagnostics.model.providerKey).toBe('minimax');
expect(diagnostics.model.fallbacks).toEqual(['minimax/MiniMax-M2.5']);
expect(diagnostics.runtime.heartbeatDisabled).toBe(true);
expect(diagnostics.providers.map((provider) => provider.key)).toEqual(['minimax']);
expect(diagnostics.providers.some((provider) => provider.key === YINIAN_MODEL_PROVIDER_KEY)).toBe(false);
});
it('removes the legacy placeholder model provider and auth leftovers', async () => {
modelDiagnosticsMocks.config = {
models: {
providers: {
[YINIAN_MODEL_PROVIDER_KEY]: {
baseUrl: YINIAN_MODEL_DEFAULT_BASE_URL,
api: 'openai-completions',
timeoutSeconds: 30,
models: [{ id: 'custom-model', name: 'Custom Model' }],
},
deepseek: {
baseUrl: 'https://api.deepseek.com/v1',
api: 'openai-completions',
models: [{ id: 'deepseek-v4-pro' }],
},
},
},
agents: {
defaults: {
model: {
primary: `${YINIAN_MODEL_PROVIDER_KEY}/custom-model`,
fallbacks: [`${YINIAN_MODEL_PROVIDER_KEY}/custom-model-lite`],
},
},
},
};
writeFileSync(authProfilesPath(testHome), JSON.stringify({
version: 1,
profiles: {
[YINIAN_MODEL_AUTH_PROFILE_ID]: {
type: 'api_key',
provider: YINIAN_MODEL_PROVIDER_KEY,
key: 'placeholder-secret',
},
[`${YINIAN_MODEL_PROVIDER_KEY}:legacy`]: {
type: 'api_key',
provider: YINIAN_MODEL_PROVIDER_KEY,
key: 'legacy-secret',
},
'deepseek:default': {
type: 'api_key',
provider: 'deepseek',
key: 'deepseek-secret',
},
},
order: {
[YINIAN_MODEL_PROVIDER_KEY]: [YINIAN_MODEL_AUTH_PROFILE_ID],
deepseek: ['deepseek:default'],
},
lastGood: {
[YINIAN_MODEL_PROVIDER_KEY]: YINIAN_MODEL_AUTH_PROFILE_ID,
deepseek: 'deepseek:default',
},
}, null, 2));
const {
buildYinianModelConfigDiagnostics,
ensureYinianModelRuntimeConfigured,
} = await import('@electron/utils/model-diagnostics');
await ensureYinianModelRuntimeConfigured();
const config = modelDiagnosticsMocks.config as {
models: { providers: Record<string, unknown> };
agents: { defaults: { model: { primary?: string; fallbacks?: string[] } } };
};
expect(config.models.providers[YINIAN_MODEL_PROVIDER_KEY]).toBeUndefined();
expect(config.models.providers.deepseek).toEqual(expect.objectContaining({
baseUrl: 'https://api.deepseek.com/v1',
}));
expect(config.agents.defaults.model.primary).toBeUndefined();
expect(config.agents.defaults.model.fallbacks).toEqual([]);
const authStore = JSON.parse(readFileSync(authProfilesPath(testHome), 'utf8')) as {
profiles: Record<string, unknown>;
order?: Record<string, string[]>;
lastGood?: Record<string, string>;
};
expect(authStore.profiles[YINIAN_MODEL_AUTH_PROFILE_ID]).toBeUndefined();
expect(authStore.profiles[`${YINIAN_MODEL_PROVIDER_KEY}:legacy`]).toBeUndefined();
expect(authStore.profiles['deepseek:default']).toEqual(expect.objectContaining({
provider: 'deepseek',
}));
expect(authStore.order?.[YINIAN_MODEL_PROVIDER_KEY]).toBeUndefined();
expect(authStore.order?.deepseek).toEqual(['deepseek:default']);
expect(authStore.lastGood?.[YINIAN_MODEL_PROVIDER_KEY]).toBeUndefined();
expect(authStore.lastGood?.deepseek).toBe('deepseek:default');
const diagnostics = await buildYinianModelConfigDiagnostics();
expect(diagnostics.model.primary).toBeNull();
expect(diagnostics.providers).toEqual([]);
expect(diagnostics.authProfiles.providers).toEqual([]);
});
it('preserves an existing custom default model during runtime repair', async () => {
modelDiagnosticsMocks.config = {
models: {
providers: {
'custom-main': {
baseUrl: 'https://llm.example.test/v1',
api: 'openai-completions',
models: [{ id: 'tenant-model' }],
},
},
},
agents: {
defaults: {
model: {
primary: 'custom-main/tenant-model',
fallbacks: ['custom-main/tenant-model-lite'],
},
},
},
};
writeFileSync(authProfilesPath(testHome), JSON.stringify({
version: 1,
profiles: {
'custom-main:default': {
type: 'api_key',
provider: 'custom-main',
key: 'custom-secret',
},
},
}, null, 2));
const {
buildYinianModelConfigDiagnostics,
ensureYinianModelRuntimeConfigured,
} = await import('@electron/utils/model-diagnostics');
await ensureYinianModelRuntimeConfigured();
const config = modelDiagnosticsMocks.config as {
models: { providers: Record<string, unknown> };
agents: { defaults: { model: { primary: string; fallbacks: string[] } } };
};
expect(config.models.providers[YINIAN_MODEL_PROVIDER_KEY]).toBeUndefined();
expect(config.agents.defaults.model.primary).toBe('custom-main/tenant-model');
expect(config.agents.defaults.model.fallbacks).toEqual(['custom-main/tenant-model-lite']);
const diagnostics = await buildYinianModelConfigDiagnostics();
expect(diagnostics.ok).toBe(true);
expect(diagnostics.model.primary).toBe('minimax/MiniMax-M2.7');
expect(diagnostics.runtime.heartbeatDisabled).toBe(true);
expect(diagnostics.checks.find((check) => check.id === 'auth-profile')?.status).toBe('ok');
expect(diagnostics.model.providerKey).toBe('custom-main');
expect(diagnostics.providers.map((provider) => provider.key)).toEqual(['custom-main']);
expect(diagnostics.authProfiles.providers.map((provider) => provider.provider)).toEqual(['custom-main']);
});
it('reports only the active DeepSeek provider when other configured providers exist', async () => {
modelDiagnosticsMocks.config = {
models: {
providers: {
'minimax-portal': {
baseUrl: 'https://api.minimax.io/anthropic',
api: 'anthropic-messages',
models: [{ id: 'MiniMax-M3' }],
},
deepseek: {
baseUrl: 'https://api.deepseek.com/v1',
api: 'openai-completions',
models: [{ id: 'deepseek-v4-pro' }],
},
},
},
agents: {
defaults: {
model: {
primary: 'deepseek/deepseek-v4-pro',
fallbacks: [],
},
},
},
};
writeFileSync(authProfilesPath(testHome), JSON.stringify({
version: 1,
profiles: {
'minimax-portal:default': {
type: 'api_key',
provider: 'minimax-portal',
key: 'minimax-secret',
},
'deepseek:default': {
type: 'api_key',
provider: 'deepseek',
key: 'deepseek-secret',
},
},
}, null, 2));
const {
buildYinianModelConfigDiagnostics,
} = await import('@electron/utils/model-diagnostics');
const diagnostics = await buildYinianModelConfigDiagnostics();
expect(diagnostics.ok).toBe(true);
expect(diagnostics.model.primary).toBe('deepseek/deepseek-v4-pro');
expect(diagnostics.providers.map((provider) => provider.key)).toEqual(['deepseek']);
expect(diagnostics.authProfiles.providers.map((provider) => provider.provider)).toEqual(['deepseek']);
});
});