feat: add tool status management and localization for skill installation
- Updated chat message types to include tool statuses. - Enhanced localization files for English, Thai, and Chinese to support new tool status messages. - Modified HomePage and SkillsPage components to handle tool statuses in chat messages. - Implemented tool status merging and updating logic in the chat store. - Added handling for tool status events in the gateway event processing. - Created tests for chat message rendering with tool statuses and skill installation shortcuts. - Improved gateway event dispatching for tool lifecycle events.
This commit is contained in:
137
tests/chat-runtime-context.test.ts
Normal file
137
tests/chat-runtime-context.test.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
// @vitest-environment node
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const mocks = vi.hoisted(() => {
|
||||
const sessionMessages: any[] = [];
|
||||
|
||||
return {
|
||||
sessionMessages,
|
||||
providerChat: vi.fn(),
|
||||
appendMessage: vi.fn((_: string, message: unknown) => {
|
||||
sessionMessages.push(message);
|
||||
}),
|
||||
getOrCreate: vi.fn(() => ({
|
||||
key: 'agent:test:main',
|
||||
messages: [...sessionMessages],
|
||||
updatedAt: Date.now(),
|
||||
})),
|
||||
setActiveRun: vi.fn(),
|
||||
clearActiveRun: vi.fn(),
|
||||
appendTranscriptLine: vi.fn(),
|
||||
maybeHandleBrowserOpenMessage: vi.fn(() => false),
|
||||
maybeHandleSkillInstallMessage: vi.fn(() => false),
|
||||
logger: {
|
||||
error: vi.fn(),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@electron/providers', () => ({
|
||||
createProvider: vi.fn(() => ({
|
||||
chat: mocks.providerChat,
|
||||
})),
|
||||
}));
|
||||
|
||||
vi.mock('@electron/service/provider-api-service', () => ({
|
||||
providerApiService: {
|
||||
getDefault: () => ({ accountId: 'provider-1' }),
|
||||
getAccounts: () => [
|
||||
{
|
||||
id: 'provider-1',
|
||||
model: 'gpt-4o-mini',
|
||||
vendorId: 'openai',
|
||||
label: 'OpenAI',
|
||||
},
|
||||
],
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('../electron/gateway/session-store', () => ({
|
||||
sessionStore: {
|
||||
appendMessage: mocks.appendMessage,
|
||||
getOrCreate: mocks.getOrCreate,
|
||||
setActiveRun: mocks.setActiveRun,
|
||||
clearActiveRun: mocks.clearActiveRun,
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@electron/utils/token-usage-writer', () => ({
|
||||
appendTranscriptLine: mocks.appendTranscriptLine,
|
||||
}));
|
||||
|
||||
vi.mock('../electron/gateway/browser-shortcut', () => ({
|
||||
maybeHandleBrowserOpenMessage: mocks.maybeHandleBrowserOpenMessage,
|
||||
}));
|
||||
|
||||
vi.mock('../electron/gateway/skill-install-shortcut', () => ({
|
||||
maybeHandleSkillInstallMessage: mocks.maybeHandleSkillInstallMessage,
|
||||
}));
|
||||
|
||||
vi.mock('@electron/service/logger', () => ({
|
||||
default: mocks.logger,
|
||||
}));
|
||||
|
||||
function createStream(chunks: Array<{ result?: string; usage?: unknown }>) {
|
||||
return {
|
||||
async *[Symbol.asyncIterator]() {
|
||||
for (const chunk of chunks) {
|
||||
yield chunk;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function flushAsyncTasks(): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, 0));
|
||||
}
|
||||
|
||||
describe('chat runtime context', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mocks.sessionMessages.length = 0;
|
||||
mocks.maybeHandleBrowserOpenMessage.mockReturnValue(false);
|
||||
mocks.maybeHandleSkillInstallMessage.mockReturnValue(false);
|
||||
mocks.providerChat.mockResolvedValue(createStream([{ result: 'done' }]));
|
||||
});
|
||||
|
||||
it('prepends the zn-ai runtime context before provider chat runs', async () => {
|
||||
const { handleChatSend } = await import('../electron/gateway/handlers/chat');
|
||||
|
||||
const result = handleChatSend(
|
||||
{
|
||||
sessionKey: 'agent:test:main',
|
||||
message: {
|
||||
role: 'user',
|
||||
content: '帮我看一下这个网页',
|
||||
},
|
||||
},
|
||||
vi.fn(),
|
||||
);
|
||||
|
||||
expect(result.runId).toBeTypeOf('string');
|
||||
|
||||
await flushAsyncTasks();
|
||||
|
||||
expect(mocks.providerChat).toHaveBeenCalledTimes(1);
|
||||
const [messages, model] = mocks.providerChat.mock.calls[0] ?? [];
|
||||
|
||||
expect(model).toBe('gpt-4o-mini');
|
||||
expect(messages).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
role: 'system',
|
||||
content: expect.stringContaining('browser.open_url'),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
role: 'user',
|
||||
content: '帮我看一下这个网页',
|
||||
}),
|
||||
]),
|
||||
);
|
||||
expect(messages[0]).toMatchObject({
|
||||
role: 'system',
|
||||
content: expect.stringContaining('skills.install'),
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user