[verified] Fix group chat agent member sync (#877)
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
||||
|
||||
const { socketHandlers, mockSocket, mockIo } = vi.hoisted(() => {
|
||||
const socketHandlers = new Map<string, (...args: any[]) => void>()
|
||||
const mockSocket: any = {
|
||||
id: 'socket-1',
|
||||
connected: true,
|
||||
io: { on: vi.fn() },
|
||||
on: vi.fn((event: string, handler: (...args: any[]) => void) => {
|
||||
socketHandlers.set(event, handler)
|
||||
if (event === 'connect') queueMicrotask(() => handler())
|
||||
return mockSocket
|
||||
}),
|
||||
emit: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
}
|
||||
const mockIo = vi.fn(() => mockSocket)
|
||||
return { socketHandlers, mockSocket, mockIo }
|
||||
})
|
||||
|
||||
vi.mock('socket.io-client', () => ({
|
||||
io: mockIo,
|
||||
}))
|
||||
|
||||
vi.mock('../../packages/server/src/services/auth', () => ({
|
||||
getToken: vi.fn(async () => 'test-token'),
|
||||
}))
|
||||
|
||||
import { AgentClients } from '../../packages/server/src/services/hermes/group-chat/agent-clients'
|
||||
import { groupChatRoutes, setGroupChatServer } from '../../packages/server/src/routes/hermes/group-chat'
|
||||
|
||||
function routeHandler(path: string, method: string) {
|
||||
const layer = (groupChatRoutes as any).stack.find((item: any) => item.path === path && item.methods.includes(method))
|
||||
if (!layer) throw new Error(`Route not found: ${method} ${path}`)
|
||||
return layer.stack[0]
|
||||
}
|
||||
|
||||
describe('Group Chat member/agent identity sync', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
socketHandlers.clear()
|
||||
})
|
||||
|
||||
it('uses the persisted group-chat agent id as the runtime agent id and socket user id', async () => {
|
||||
const clients = new AgentClients()
|
||||
|
||||
const client = await clients.createAgent({
|
||||
agentId: 'agent-stable-1',
|
||||
profile: 'default',
|
||||
name: 'Worker',
|
||||
description: '',
|
||||
invited: 0,
|
||||
} as any)
|
||||
|
||||
expect(client.agentId).toBe('agent-stable-1')
|
||||
expect(mockIo).toHaveBeenCalledWith(
|
||||
'http://127.0.0.1:8648/group-chat',
|
||||
expect.objectContaining({
|
||||
auth: expect.objectContaining({
|
||||
token: 'test-token',
|
||||
userId: 'agent-stable-1',
|
||||
name: 'Worker',
|
||||
source: 'agent',
|
||||
agentSocketSecret: expect.any(String),
|
||||
}),
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('passes the same persisted agent id into the runtime client when adding an agent', async () => {
|
||||
const addRoomAgent = vi.fn((roomId: string, agentId: string, profile: string, name: string, description: string, invited: number) => ({
|
||||
id: 'row-1', roomId, agentId, profile, name, description, invited,
|
||||
}))
|
||||
const chatServer = {
|
||||
getStorage: () => ({
|
||||
getRoomAgents: vi.fn(() => []),
|
||||
addRoomAgent,
|
||||
}),
|
||||
agentClients: {
|
||||
createAgent: vi.fn(async () => ({ agentId: 'runtime-agent' })),
|
||||
addAgentToRoom: vi.fn(async () => undefined),
|
||||
},
|
||||
}
|
||||
setGroupChatServer(chatServer as any)
|
||||
|
||||
const handler = routeHandler('/api/hermes/group-chat/rooms/:roomId/agents', 'POST')
|
||||
const ctx: any = {
|
||||
params: { roomId: 'room-1' },
|
||||
request: { body: { profile: 'default', name: 'Worker' } },
|
||||
status: 200,
|
||||
body: undefined,
|
||||
}
|
||||
await handler(ctx, async () => {})
|
||||
|
||||
const persisted = ctx.body.agent
|
||||
expect(persisted.agentId).toBeTruthy()
|
||||
expect(chatServer.agentClients.createAgent).toHaveBeenCalledWith(expect.objectContaining({
|
||||
agentId: persisted.agentId,
|
||||
profile: 'default',
|
||||
name: 'Worker',
|
||||
}))
|
||||
})
|
||||
|
||||
it('removes the runtime agent by persisted agentId and returns synchronized room state', async () => {
|
||||
const agentsBefore = [{ id: 'row-1', roomId: 'room-1', agentId: 'agent-stable-1', profile: 'default', name: 'Worker', description: '', invited: 0 }]
|
||||
const storage = {
|
||||
getRoomAgent: vi.fn(() => agentsBefore[0]),
|
||||
getRoomAgents: vi.fn(() => []),
|
||||
removeRoomMembersForAgent: vi.fn(),
|
||||
removeRoomAgent: vi.fn(),
|
||||
getRoomMembers: vi.fn(() => [{ id: 'member-1', userId: 'human-1', name: 'Han', description: '', joinedAt: 1 }]),
|
||||
}
|
||||
const chatServer = {
|
||||
getStorage: () => storage,
|
||||
agentClients: { removeAgentFromRoom: vi.fn() },
|
||||
}
|
||||
setGroupChatServer(chatServer as any)
|
||||
|
||||
const handler = routeHandler('/api/hermes/group-chat/rooms/:roomId/agents/:agentId', 'DELETE')
|
||||
const ctx: any = {
|
||||
params: { roomId: 'room-1', agentId: 'row-1' },
|
||||
status: 200,
|
||||
body: undefined,
|
||||
}
|
||||
await handler(ctx, async () => {})
|
||||
|
||||
expect(chatServer.agentClients.removeAgentFromRoom).toHaveBeenCalledWith('room-1', 'agent-stable-1')
|
||||
expect(storage.removeRoomMembersForAgent).toHaveBeenCalledWith('room-1', agentsBefore[0])
|
||||
expect(storage.removeRoomAgent).toHaveBeenCalledWith('room-1', 'row-1')
|
||||
expect(ctx.body).toEqual({
|
||||
success: true,
|
||||
agents: [],
|
||||
members: [{ id: 'member-1', userId: 'human-1', name: 'Han', description: '', joinedAt: 1 }],
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user