Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Haze <hazeone@users.noreply.github.com>
160 lines
6.7 KiB
TypeScript
160 lines
6.7 KiB
TypeScript
import { closeElectronApp, expect, getStableWindow, test } from './fixtures/electron';
|
|
|
|
const alphaModelRef = 'custom-alpha123/model-alpha';
|
|
const betaModelRef = 'custom-beta5678/provider/model-beta';
|
|
|
|
test.describe('ClawX chat model picker', () => {
|
|
test('switches the current agent model without requesting a gateway refresh', async ({ launchElectronApp }) => {
|
|
const app = await launchElectronApp({ skipSetup: true });
|
|
|
|
try {
|
|
await app.evaluate(async ({ app: _app }, refs) => {
|
|
const { ipcMain } = process.mainModule!.require('electron') as typeof import('electron');
|
|
|
|
let currentModelRef = refs.alphaModelRef;
|
|
const hostRequests: Array<{ path: string; method: string; body: unknown }> = [];
|
|
const now = new Date().toISOString();
|
|
const makeResponse = (json: unknown, status = 200) => ({
|
|
ok: true,
|
|
data: {
|
|
status,
|
|
ok: status >= 200 && status < 300,
|
|
json,
|
|
},
|
|
});
|
|
|
|
const agentsSnapshot = () => ({
|
|
success: true,
|
|
agents: [{
|
|
id: 'main',
|
|
name: 'Main',
|
|
isDefault: true,
|
|
modelDisplay: currentModelRef.split('/').slice(1).join('/'),
|
|
modelRef: currentModelRef,
|
|
overrideModelRef: currentModelRef,
|
|
inheritedModel: false,
|
|
workspace: '~/.openclaw/workspace',
|
|
agentDir: '~/.openclaw/agents/main/agent',
|
|
mainSessionKey: 'agent:main:main',
|
|
channelTypes: [],
|
|
}],
|
|
defaultAgentId: 'main',
|
|
defaultModelRef: refs.alphaModelRef,
|
|
configuredChannelTypes: [],
|
|
channelOwners: {},
|
|
channelAccountOwners: {},
|
|
});
|
|
|
|
ipcMain.removeHandler('gateway:status');
|
|
ipcMain.handle('gateway:status', async () => ({ state: 'running', port: 18789, pid: 12345 }));
|
|
|
|
ipcMain.removeHandler('gateway:rpc');
|
|
ipcMain.handle('gateway:rpc', async (_event: unknown, method: string, params: unknown) => {
|
|
hostRequests.push({ path: `gateway:${method}`, method: 'RPC', body: params ?? null });
|
|
if (method === 'sessions.list') {
|
|
return { success: true, result: { sessions: [{ key: 'agent:main:main', displayName: 'main' }] } };
|
|
}
|
|
if (method === 'chat.history') {
|
|
return { success: true, result: { messages: [] } };
|
|
}
|
|
return { success: true, result: {} };
|
|
});
|
|
|
|
ipcMain.removeHandler('hostapi:fetch');
|
|
ipcMain.handle('hostapi:fetch', async (_event: unknown, request: { path?: string; method?: string; body?: string | null }) => {
|
|
const path = request?.path ?? '';
|
|
const method = request?.method ?? 'GET';
|
|
const body = request?.body ? JSON.parse(request.body) : null;
|
|
hostRequests.push({ path, method, body });
|
|
|
|
if (path === '/api/gateway/status' && method === 'GET') {
|
|
return makeResponse({ state: 'running', port: 18789, pid: 12345, gatewayReady: true });
|
|
}
|
|
if (path === '/api/agents' && method === 'GET') {
|
|
return makeResponse(agentsSnapshot());
|
|
}
|
|
if (path === '/api/agents/main/model' && method === 'PUT') {
|
|
currentModelRef = body?.modelRef ?? refs.alphaModelRef;
|
|
return makeResponse(agentsSnapshot());
|
|
}
|
|
if (path === '/api/provider-accounts' && method === 'GET') {
|
|
return makeResponse([
|
|
{
|
|
id: 'alpha1234',
|
|
vendorId: 'custom',
|
|
label: 'Alpha',
|
|
authMode: 'api_key',
|
|
baseUrl: 'http://127.0.0.1:1111/v1',
|
|
model: 'model-alpha',
|
|
enabled: true,
|
|
isDefault: true,
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
},
|
|
{
|
|
id: 'beta5678',
|
|
vendorId: 'custom',
|
|
label: 'Beta',
|
|
authMode: 'api_key',
|
|
baseUrl: 'http://127.0.0.1:2222/v1',
|
|
model: refs.betaModelRef,
|
|
enabled: true,
|
|
isDefault: false,
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
},
|
|
]);
|
|
}
|
|
if (path === '/api/providers' && method === 'GET') {
|
|
return makeResponse([
|
|
{ id: 'alpha1234', type: 'custom', name: 'Alpha', enabled: true, hasKey: true, keyMasked: 'sk-***', createdAt: now, updatedAt: now },
|
|
{ id: 'beta5678', type: 'custom', name: 'Beta', enabled: true, hasKey: true, keyMasked: 'sk-***', createdAt: now, updatedAt: now },
|
|
]);
|
|
}
|
|
if (path === '/api/provider-vendors' && method === 'GET') {
|
|
return makeResponse([]);
|
|
}
|
|
if (path === '/api/provider-accounts/default' && method === 'GET') {
|
|
return makeResponse({ accountId: 'alpha1234' });
|
|
}
|
|
|
|
return makeResponse({});
|
|
});
|
|
|
|
(globalThis as typeof globalThis & { __chatModelPickerRequests?: typeof hostRequests }).__chatModelPickerRequests = hostRequests;
|
|
}, { alphaModelRef, betaModelRef });
|
|
|
|
const page = await getStableWindow(app);
|
|
await page.reload();
|
|
await expect(page.getByTestId('main-layout')).toBeVisible();
|
|
await app.evaluate(({ BrowserWindow }) => {
|
|
const win = BrowserWindow.getAllWindows()[0];
|
|
win?.webContents.send('gateway:status-changed', { state: 'running', port: 18789, pid: 12345, gatewayReady: true });
|
|
});
|
|
|
|
await expect(page.getByTestId('chat-model-picker-button')).toContainText('model-alpha');
|
|
await page.getByTestId('chat-model-picker-button').click();
|
|
await expect(page.getByTestId('chat-model-picker-menu')).toBeVisible();
|
|
await expect(page.getByTestId('chat-model-picker-menu')).toContainText('provider/model-beta');
|
|
await page.getByTestId('chat-model-picker-menu').getByRole('button', { name: 'provider/model-beta' }).click();
|
|
await expect(page.getByTestId('chat-model-picker-button')).toContainText('provider/model-beta');
|
|
|
|
const requests = await app.evaluate(() => (
|
|
(globalThis as typeof globalThis & { __chatModelPickerRequests?: Array<{ path: string; method: string; body: unknown }> }).__chatModelPickerRequests ?? []
|
|
));
|
|
expect(requests).toContainEqual({
|
|
path: '/api/agents/main/model',
|
|
method: 'PUT',
|
|
body: { modelRef: betaModelRef },
|
|
});
|
|
expect(requests.some((request) =>
|
|
request.path === '/api/gateway/restart'
|
|
|| request.path === '/api/gateway/start'
|
|
|| request.path === 'gateway:config.patch'
|
|
)).toBe(false);
|
|
} finally {
|
|
await closeElectronApp(app);
|
|
}
|
|
});
|
|
});
|