kimi-code/packages/node-sdk/test/session-set-model.test.ts
2026-05-22 15:54:50 +08:00

177 lines
5.4 KiB
TypeScript

import { join } from 'node:path';
import { FileTokenStorage, type TokenInfo } from '@moonshot-ai/kimi-code-oauth';
import { afterEach, describe, expect, it } from 'vitest';
import { KimiHarness, type KimiError } from '#/index';
import { makeTempDir, removeTempDirs, waitForAgentWireEvent } from './session-runtime-helpers';
import { TEST_IDENTITY } from './test-identity';
const tempDirs: string[] = [];
function freshToken(): TokenInfo {
return {
accessToken: 'oauth-access-token',
refreshToken: 'oauth-refresh-token',
expiresAt: Math.floor(Date.now() / 1000) + 3600,
scope: '',
tokenType: 'Bearer',
expiresIn: 3600,
};
}
afterEach(async () => {
await removeTempDirs(tempDirs);
});
describe('Session.setModel', () => {
it('updates the runtime model and sends config.update with the resolved model', async () => {
const homeDir = await makeTempDir(tempDirs, 'kimi-sdk-model-home-');
const workDir = await makeTempDir(tempDirs, 'kimi-sdk-model-work-');
const harness = new KimiHarness({ homeDir, identity: TEST_IDENTITY });
try {
await configureLocalProvider(harness);
const session = await harness.createSession({
id: 'ses_model_wire',
workDir,
model: 'initial-model',
});
await session.setModel('next-model');
await expect(session.getStatus()).resolves.toMatchObject({ model: 'next-model' });
const configEvent = await waitForAgentWireEvent(
homeDir,
session.id,
'config.update',
(event) => event['modelAlias'] === 'next-model',
);
expect(configEvent).toMatchObject({
type: 'config.update',
modelAlias: 'next-model',
});
expect(configEvent).not.toHaveProperty('provider');
} finally {
await harness.close();
}
});
it('resolves managed OAuth aliases before updating the runtime provider', async () => {
const homeDir = await makeTempDir(tempDirs, 'kimi-sdk-model-home-');
const workDir = await makeTempDir(tempDirs, 'kimi-sdk-model-work-');
await new FileTokenStorage(join(homeDir, 'credentials')).save('kimi-code', freshToken());
const harness = new KimiHarness({ homeDir, identity: TEST_IDENTITY });
try {
await harness.setConfig({
providers: {
'managed:kimi-code': {
type: 'kimi',
baseUrl: 'https://api.kimi.com/coding/v1',
apiKey: '',
oauth: { storage: 'file', key: 'oauth/kimi-code' },
},
},
models: {
'kimi-code/initial': {
provider: 'managed:kimi-code',
model: 'kimi-initial',
maxContextSize: 262144,
},
'kimi-code/kimi-for-coding': {
provider: 'managed:kimi-code',
model: 'kimi-for-coding',
maxContextSize: 262144,
},
},
defaultModel: 'kimi-code/initial',
});
const session = await harness.createSession({
id: 'ses_model_oauth_wire',
workDir,
model: 'kimi-code/initial',
});
await session.setModel('kimi-code/kimi-for-coding');
await expect(session.getStatus()).resolves.toMatchObject({
model: 'kimi-code/kimi-for-coding',
});
const configEvent = await waitForAgentWireEvent(
homeDir,
session.id,
'config.update',
(event) => event['modelAlias'] === 'kimi-code/kimi-for-coding',
);
expect(configEvent).toMatchObject({
type: 'config.update',
modelAlias: 'kimi-code/kimi-for-coding',
});
expect(configEvent).not.toHaveProperty('provider');
} finally {
await harness.close();
}
});
it('rejects empty model names', async () => {
const homeDir = await makeTempDir(tempDirs, 'kimi-sdk-model-home-');
const workDir = await makeTempDir(tempDirs, 'kimi-sdk-model-work-');
const harness = new KimiHarness({ homeDir, identity: TEST_IDENTITY });
try {
await configureLocalProvider(harness);
const session = await harness.createSession({ id: 'ses_model_empty', workDir });
await expect(session.setModel(' ')).rejects.toMatchObject({
name: 'KimiError',
code: 'session.model_empty',
} satisfies Partial<KimiError>);
} finally {
await harness.close();
}
});
it('rejects after the session is closed', async () => {
const homeDir = await makeTempDir(tempDirs, 'kimi-sdk-model-home-');
const workDir = await makeTempDir(tempDirs, 'kimi-sdk-model-work-');
const harness = new KimiHarness({ homeDir, identity: TEST_IDENTITY });
try {
await configureLocalProvider(harness);
const session = await harness.createSession({ id: 'ses_model_closed', workDir });
await session.close();
await expect(session.setModel('next-model')).rejects.toMatchObject({
name: 'KimiError',
code: 'session.closed',
} satisfies Partial<KimiError>);
} finally {
await harness.close();
}
});
});
async function configureLocalProvider(harness: KimiHarness): Promise<void> {
await harness.setConfig({
providers: {
local: {
type: 'kimi',
apiKey: 'sk-test',
},
},
models: {
'initial-model': {
provider: 'local',
model: 'initial-model',
maxContextSize: 262144,
},
'next-model': {
provider: 'local',
model: 'next-model',
maxContextSize: 262144,
},
},
defaultProvider: 'local',
});
}