feat(agents): support chat to agent (#403)
This commit is contained in:
138
tests/unit/chat-input.test.tsx
Normal file
138
tests/unit/chat-input.test.tsx
Normal file
@@ -0,0 +1,138 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { ChatInput } from '@/pages/Chat/ChatInput';
|
||||
|
||||
const { agentsState, chatState, gatewayState } = vi.hoisted(() => ({
|
||||
agentsState: {
|
||||
agents: [] as Array<Record<string, unknown>>,
|
||||
},
|
||||
chatState: {
|
||||
currentAgentId: 'main',
|
||||
},
|
||||
gatewayState: {
|
||||
status: { state: 'running', port: 18789 },
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@/stores/agents', () => ({
|
||||
useAgentsStore: (selector: (state: typeof agentsState) => unknown) => selector(agentsState),
|
||||
}));
|
||||
|
||||
vi.mock('@/stores/chat', () => ({
|
||||
useChatStore: (selector: (state: typeof chatState) => unknown) => selector(chatState),
|
||||
}));
|
||||
|
||||
vi.mock('@/stores/gateway', () => ({
|
||||
useGatewayStore: (selector: (state: typeof gatewayState) => unknown) => selector(gatewayState),
|
||||
}));
|
||||
|
||||
vi.mock('@/lib/host-api', () => ({
|
||||
hostApiFetch: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@/lib/api-client', () => ({
|
||||
invokeIpc: vi.fn(),
|
||||
}));
|
||||
|
||||
function translate(key: string, vars?: Record<string, unknown>): string {
|
||||
switch (key) {
|
||||
case 'composer.attachFiles':
|
||||
return 'Attach files';
|
||||
case 'composer.pickAgent':
|
||||
return 'Choose agent';
|
||||
case 'composer.clearTarget':
|
||||
return 'Clear target agent';
|
||||
case 'composer.targetChip':
|
||||
return `@${String(vars?.agent ?? '')}`;
|
||||
case 'composer.agentPickerTitle':
|
||||
return 'Route the next message to another agent';
|
||||
case 'composer.gatewayDisconnectedPlaceholder':
|
||||
return 'Gateway not connected...';
|
||||
case 'composer.send':
|
||||
return 'Send';
|
||||
case 'composer.stop':
|
||||
return 'Stop';
|
||||
case 'composer.gatewayConnected':
|
||||
return 'connected';
|
||||
case 'composer.gatewayStatus':
|
||||
return `gateway ${String(vars?.state ?? '')} | port: ${String(vars?.port ?? '')} ${String(vars?.pid ?? '')}`.trim();
|
||||
case 'composer.retryFailedAttachments':
|
||||
return 'Retry failed attachments';
|
||||
default:
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: translate,
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('ChatInput agent targeting', () => {
|
||||
beforeEach(() => {
|
||||
agentsState.agents = [];
|
||||
chatState.currentAgentId = 'main';
|
||||
gatewayState.status = { state: 'running', port: 18789 };
|
||||
});
|
||||
|
||||
it('hides the @agent picker when only one agent is configured', () => {
|
||||
agentsState.agents = [
|
||||
{
|
||||
id: 'main',
|
||||
name: 'Main',
|
||||
isDefault: true,
|
||||
modelDisplay: 'MiniMax',
|
||||
inheritedModel: true,
|
||||
workspace: '~/.openclaw/workspace',
|
||||
agentDir: '~/.openclaw/agents/main/agent',
|
||||
mainSessionKey: 'agent:main:main',
|
||||
channelTypes: [],
|
||||
},
|
||||
];
|
||||
|
||||
render(<ChatInput onSend={vi.fn()} />);
|
||||
|
||||
expect(screen.queryByTitle('Choose agent')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('lets the user select an agent target and sends it with the message', () => {
|
||||
const onSend = vi.fn();
|
||||
agentsState.agents = [
|
||||
{
|
||||
id: 'main',
|
||||
name: 'Main',
|
||||
isDefault: true,
|
||||
modelDisplay: 'MiniMax',
|
||||
inheritedModel: true,
|
||||
workspace: '~/.openclaw/workspace',
|
||||
agentDir: '~/.openclaw/agents/main/agent',
|
||||
mainSessionKey: 'agent:main:main',
|
||||
channelTypes: [],
|
||||
},
|
||||
{
|
||||
id: 'research',
|
||||
name: 'Research',
|
||||
isDefault: false,
|
||||
modelDisplay: 'Claude',
|
||||
inheritedModel: false,
|
||||
workspace: '~/.openclaw/workspace-research',
|
||||
agentDir: '~/.openclaw/agents/research/agent',
|
||||
mainSessionKey: 'agent:research:desk',
|
||||
channelTypes: [],
|
||||
},
|
||||
];
|
||||
|
||||
render(<ChatInput onSend={onSend} />);
|
||||
|
||||
fireEvent.click(screen.getByTitle('Choose agent'));
|
||||
fireEvent.click(screen.getByText('Research'));
|
||||
|
||||
expect(screen.getByText('@Research')).toBeInTheDocument();
|
||||
|
||||
fireEvent.change(screen.getByRole('textbox'), { target: { value: 'Hello direct agent' } });
|
||||
fireEvent.click(screen.getByTitle('Send'));
|
||||
|
||||
expect(onSend).toHaveBeenCalledWith('Hello direct agent', undefined, 'research');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user