From 3e1591d4042f2031cc2f08dc011e70751d857dc1 Mon Sep 17 00:00:00 2001 From: matt burnett Date: Sat, 28 Jun 2025 12:35:41 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20fix:=20Remove=20`versions`=20and?= =?UTF-8?q?=20`=5F=5Fv`=20when=20Duplicating=20an=20Agent=20(#8115)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert "Add tests for agent duplication controller" This reverts commit 3e7beb1cc336bcfe1c57411e9c151f5e6aa927e4. --- .../controllers/agents/__tests__/v1.spec.js | 195 ++++++++++++++++++ api/server/controllers/agents/v1.js | 2 + 2 files changed, 197 insertions(+) create mode 100644 api/server/controllers/agents/__tests__/v1.spec.js diff --git a/api/server/controllers/agents/__tests__/v1.spec.js b/api/server/controllers/agents/__tests__/v1.spec.js new file mode 100644 index 0000000000..b097cd98ce --- /dev/null +++ b/api/server/controllers/agents/__tests__/v1.spec.js @@ -0,0 +1,195 @@ +const { duplicateAgent } = require('../v1'); +const { getAgent, createAgent } = require('~/models/Agent'); +const { getActions } = require('~/models/Action'); +const { nanoid } = require('nanoid'); + +jest.mock('~/models/Agent'); +jest.mock('~/models/Action'); +jest.mock('nanoid'); + +describe('duplicateAgent', () => { + let req, res; + + beforeEach(() => { + req = { + params: { id: 'agent_123' }, + user: { id: 'user_456' }, + }; + res = { + status: jest.fn().mockReturnThis(), + json: jest.fn(), + }; + jest.clearAllMocks(); + }); + + it('should duplicate an agent successfully', async () => { + const mockAgent = { + id: 'agent_123', + name: 'Test Agent', + description: 'Test Description', + instructions: 'Test Instructions', + provider: 'openai', + model: 'gpt-4', + tools: ['file_search'], + actions: [], + author: 'user_789', + versions: [{ name: 'Test Agent', version: 1 }], + __v: 0, + }; + + const mockNewAgent = { + id: 'agent_new_123', + name: 'Test Agent (1/2/23, 12:34)', + description: 'Test Description', + instructions: 'Test Instructions', + provider: 'openai', + model: 'gpt-4', + tools: ['file_search'], + actions: [], + author: 'user_456', + versions: [ + { + name: 'Test Agent (1/2/23, 12:34)', + description: 'Test Description', + instructions: 'Test Instructions', + provider: 'openai', + model: 'gpt-4', + tools: ['file_search'], + actions: [], + createdAt: new Date(), + updatedAt: new Date(), + }, + ], + }; + + getAgent.mockResolvedValue(mockAgent); + getActions.mockResolvedValue([]); + nanoid.mockReturnValue('new_123'); + createAgent.mockResolvedValue(mockNewAgent); + + await duplicateAgent(req, res); + + expect(getAgent).toHaveBeenCalledWith({ id: 'agent_123' }); + expect(getActions).toHaveBeenCalledWith({ agent_id: 'agent_123' }, true); + expect(createAgent).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'agent_new_123', + author: 'user_456', + name: expect.stringContaining('Test Agent ('), + description: 'Test Description', + instructions: 'Test Instructions', + provider: 'openai', + model: 'gpt-4', + tools: ['file_search'], + actions: [], + }), + ); + + expect(createAgent).toHaveBeenCalledWith( + expect.not.objectContaining({ + versions: expect.anything(), + __v: expect.anything(), + }), + ); + + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith({ + agent: mockNewAgent, + actions: [], + }); + }); + + it('should ensure duplicated agent has clean versions array without nested fields', async () => { + const mockAgent = { + id: 'agent_123', + name: 'Test Agent', + description: 'Test Description', + versions: [ + { + name: 'Test Agent', + versions: [{ name: 'Nested' }], + __v: 1, + }, + ], + __v: 2, + }; + + const mockNewAgent = { + id: 'agent_new_123', + name: 'Test Agent (1/2/23, 12:34)', + description: 'Test Description', + versions: [ + { + name: 'Test Agent (1/2/23, 12:34)', + description: 'Test Description', + createdAt: new Date(), + updatedAt: new Date(), + }, + ], + }; + + getAgent.mockResolvedValue(mockAgent); + getActions.mockResolvedValue([]); + nanoid.mockReturnValue('new_123'); + createAgent.mockResolvedValue(mockNewAgent); + + await duplicateAgent(req, res); + + expect(mockNewAgent.versions).toHaveLength(1); + + const firstVersion = mockNewAgent.versions[0]; + expect(firstVersion).not.toHaveProperty('versions'); + expect(firstVersion).not.toHaveProperty('__v'); + + expect(mockNewAgent).not.toHaveProperty('__v'); + + expect(res.status).toHaveBeenCalledWith(201); + }); + + it('should return 404 if agent not found', async () => { + getAgent.mockResolvedValue(null); + + await duplicateAgent(req, res); + + expect(res.status).toHaveBeenCalledWith(404); + expect(res.json).toHaveBeenCalledWith({ + error: 'Agent not found', + status: 'error', + }); + }); + + it('should handle tool_resources.ocr correctly', async () => { + const mockAgent = { + id: 'agent_123', + name: 'Test Agent', + tool_resources: { + ocr: { enabled: true, config: 'test' }, + other: { should: 'not be copied' }, + }, + }; + + getAgent.mockResolvedValue(mockAgent); + getActions.mockResolvedValue([]); + nanoid.mockReturnValue('new_123'); + createAgent.mockResolvedValue({ id: 'agent_new_123' }); + + await duplicateAgent(req, res); + + expect(createAgent).toHaveBeenCalledWith( + expect.objectContaining({ + tool_resources: { + ocr: { enabled: true, config: 'test' }, + }, + }), + ); + }); + + it('should handle errors gracefully', async () => { + getAgent.mockRejectedValue(new Error('Database error')); + + await duplicateAgent(req, res); + + expect(res.status).toHaveBeenCalledWith(500); + expect(res.json).toHaveBeenCalledWith({ error: 'Database error' }); + }); +}); diff --git a/api/server/controllers/agents/v1.js b/api/server/controllers/agents/v1.js index 18bd7190f0..764a2e05d4 100644 --- a/api/server/controllers/agents/v1.js +++ b/api/server/controllers/agents/v1.js @@ -242,6 +242,8 @@ const duplicateAgentHandler = async (req, res) => { createdAt: _createdAt, updatedAt: _updatedAt, tool_resources: _tool_resources = {}, + versions: _versions, + __v: _v, ...cloneData } = agent; cloneData.name = `${agent.name} (${new Date().toLocaleString('en-US', {