const mongoose = require('mongoose'); const { ResourceType, PermissionBits, PrincipalType, PrincipalModel, MAX_SUBAGENT_DEPTH, MAX_SUBAGENT_GRAPH_NODES, } = require('librechat-data-provider'); const { MongoMemoryServer } = require('mongodb-memory-server'); const mockInitializeAgent = jest.fn(); const mockValidateAgentModel = jest.fn(); jest.mock('@librechat/agents', () => ({ ...jest.requireActual('@librechat/agents'), createContentAggregator: jest.fn(() => ({ contentParts: [], aggregateContent: jest.fn(), })), })); jest.mock('@librechat/api', () => ({ ...jest.requireActual('@librechat/api'), initializeAgent: (...args) => mockInitializeAgent(...args), validateAgentModel: (...args) => mockValidateAgentModel(...args), GenerationJobManager: { setCollectedUsage: jest.fn() }, getCustomEndpointConfig: jest.fn(), createSequentialChainEdges: jest.fn(), })); /** Captured by the `getDefaultHandlers` mock so tests can drive the * `ON_TOOL_EXECUTE` pipeline with a real subagent id and observe whether * the tool context (agent, tool_resources, skill ACLs) was preserved. */ let capturedToolExecuteOptions; jest.mock('~/server/controllers/agents/callbacks', () => ({ createToolEndCallback: jest.fn(() => jest.fn()), getDefaultHandlers: jest.fn((opts) => { capturedToolExecuteOptions = opts?.toolExecuteOptions; return {}; }), })); const mockLoadToolsForExecution = jest.fn(); jest.mock('~/server/services/ToolService', () => ({ loadAgentTools: jest.fn(), loadToolsForExecution: (...args) => mockLoadToolsForExecution(...args), })); jest.mock('~/server/controllers/ModelController', () => ({ getModelsConfig: jest.fn().mockResolvedValue({}), })); let agentClientArgs; jest.mock('~/server/controllers/agents/client', () => { return jest.fn().mockImplementation((args) => { agentClientArgs = args; return {}; }); }); jest.mock('./addedConvo', () => ({ processAddedConvo: jest.fn().mockResolvedValue({ userMCPAuthMap: undefined }), })); jest.mock('~/cache', () => ({ logViolation: jest.fn(), })); const { initializeClient } = require('./initialize'); const { logger } = require('@librechat/data-schemas'); const { User, AclEntry } = require('~/db/models'); const { createAgent } = require('~/models'); jest.spyOn(logger, 'warn').mockImplementation(() => {}); const PRIMARY_ID = 'agent_primary'; const TARGET_ID = 'agent_target'; const AUTHORIZED_ID = 'agent_authorized'; describe('initializeClient — processAgent ACL gate', () => { let mongoServer; let testUser; beforeAll(async () => { mongoServer = await MongoMemoryServer.create(); await mongoose.connect(mongoServer.getUri()); }); afterAll(async () => { await mongoose.disconnect(); await mongoServer.stop(); }); beforeEach(async () => { await mongoose.connection.dropDatabase(); jest.clearAllMocks(); agentClientArgs = undefined; testUser = await User.create({ email: 'test@example.com', name: 'Test User', username: 'testuser', role: 'USER', }); mockValidateAgentModel.mockResolvedValue({ isValid: true }); }); const makeReq = () => ({ user: { id: testUser._id.toString(), role: 'USER' }, body: { conversationId: 'conv_1', files: [] }, config: { endpoints: {} }, _resumableStreamId: null, }); const makeEndpointOption = () => ({ agent: Promise.resolve({ id: PRIMARY_ID, name: 'Primary', provider: 'openai', model: 'gpt-4', tools: [], }), model_parameters: { model: 'gpt-4' }, endpoint: 'agents', }); const makePrimaryConfig = (edges) => ({ id: PRIMARY_ID, endpoint: 'agents', edges, toolDefinitions: [], toolRegistry: new Map(), userMCPAuthMap: null, tool_resources: {}, resendFiles: true, maxContextTokens: 4096, }); it('should skip handoff agent and filter its edge when user lacks VIEW access', async () => { await createAgent({ id: TARGET_ID, name: 'Target Agent', provider: 'openai', model: 'gpt-4', author: new mongoose.Types.ObjectId(), tools: [], }); const edges = [{ from: PRIMARY_ID, to: TARGET_ID, edgeType: 'handoff' }]; mockInitializeAgent.mockResolvedValue(makePrimaryConfig(edges)); await initializeClient({ req: makeReq(), res: {}, signal: new AbortController().signal, endpointOption: makeEndpointOption(), }); expect(mockInitializeAgent).toHaveBeenCalledTimes(1); expect(agentClientArgs.agent.edges).toEqual([]); }); it('should initialize handoff agent and keep its edge when user has VIEW access', async () => { const authorizedAgent = await createAgent({ id: AUTHORIZED_ID, name: 'Authorized Agent', provider: 'openai', model: 'gpt-4', author: new mongoose.Types.ObjectId(), tools: [], }); await AclEntry.create({ principalType: PrincipalType.USER, principalId: testUser._id, principalModel: PrincipalModel.USER, resourceType: ResourceType.AGENT, resourceId: authorizedAgent._id, permBits: PermissionBits.VIEW, grantedBy: testUser._id, }); const edges = [{ from: PRIMARY_ID, to: AUTHORIZED_ID, edgeType: 'handoff' }]; const requestAttachment = { file_id: 'request_file', filename: 'request.txt' }; const primaryContextAttachment = { file_id: 'primary_context', filename: 'primary.txt' }; const handoffContextAttachment = { file_id: 'handoff_context', filename: 'handoff.txt' }; const primaryConfig = { ...makePrimaryConfig(edges), attachments: [primaryContextAttachment, requestAttachment], requestAttachments: [requestAttachment], agentContextAttachments: [primaryContextAttachment], }; const handoffConfig = { id: AUTHORIZED_ID, edges: [], toolDefinitions: [], toolRegistry: new Map(), userMCPAuthMap: null, tool_resources: {}, agentContextAttachments: [handoffContextAttachment], }; let callCount = 0; mockInitializeAgent.mockImplementation(() => { callCount++; return callCount === 1 ? Promise.resolve(primaryConfig) : Promise.resolve(handoffConfig); }); await initializeClient({ req: makeReq(), res: {}, signal: new AbortController().signal, endpointOption: makeEndpointOption(), }); expect(mockInitializeAgent).toHaveBeenCalledTimes(2); expect(agentClientArgs.agent.edges).toHaveLength(1); expect(agentClientArgs.agent.edges[0].to).toBe(AUTHORIZED_ID); expect(agentClientArgs.attachments).toEqual([requestAttachment]); expect(agentClientArgs.agentContextAttachmentsByAgentId.get(PRIMARY_ID)).toEqual([ primaryContextAttachment, ]); expect(agentClientArgs.agentContextAttachmentsByAgentId.get(AUTHORIZED_ID)).toEqual([ handoffContextAttachment, ]); }); }); describe('initializeClient — subagent loading', () => { const SUBAGENT_ID = 'agent_subagent_1'; const DUPLICATE_SUBAGENT_ID = 'agent_subagent_dup'; const HANDOFF_AND_SUB_ID = 'agent_handoff_and_sub'; let mongoServer; let testUser; beforeAll(async () => { mongoServer = await MongoMemoryServer.create(); await mongoose.connect(mongoServer.getUri()); }); afterAll(async () => { await mongoose.disconnect(); await mongoServer.stop(); }); beforeEach(async () => { await mongoose.connection.dropDatabase(); jest.clearAllMocks(); agentClientArgs = undefined; capturedToolExecuteOptions = undefined; mockLoadToolsForExecution.mockReset(); mockLoadToolsForExecution.mockResolvedValue({ loadedTools: [] }); testUser = await User.create({ email: 'subagent@example.com', name: 'Subagent User', username: 'subuser', role: 'USER', }); mockValidateAgentModel.mockResolvedValue({ isValid: true }); }); /** Grant the test user VIEW on an agent so processAgent loads it. */ const grantView = async (agentDoc) => { await AclEntry.create({ principalType: PrincipalType.USER, principalId: testUser._id, principalModel: PrincipalModel.USER, resourceType: ResourceType.AGENT, resourceId: agentDoc._id, permBits: PermissionBits.VIEW, grantedBy: testUser._id, }); }; /** Build a request with the `subagents` capability enabled. */ const makeSubagentReq = () => ({ user: { id: testUser._id.toString(), role: 'USER' }, body: { conversationId: 'conv_sub', files: [] }, config: { endpoints: { agents: { capabilities: ['subagents'], }, }, }, _resumableStreamId: null, }); const makeEndpointOption = () => ({ agent: Promise.resolve({ id: PRIMARY_ID, name: 'Primary', provider: 'openai', model: 'gpt-4', tools: [], }), model_parameters: { model: 'gpt-4' }, endpoint: 'agents', }); const makePrimaryConfig = ({ edges = [], subagents, agent_ids }) => ({ id: PRIMARY_ID, endpoint: 'agents', edges, toolDefinitions: [], toolRegistry: new Map(), userMCPAuthMap: null, tool_resources: {}, resendFiles: true, maxContextTokens: 4096, subagents, agent_ids, }); const makeSubagentConfig = (id) => ({ id, endpoint: 'agents', edges: [], toolDefinitions: [{ name: 'web', description: 'web', parameters: {} }], toolRegistry: new Map([['web', { name: 'web' }]]), userMCPAuthMap: null, tool_resources: { file_search: { file_ids: ['file_1'] } }, accessibleSkillIds: ['skill_1'], actionsEnabled: true, resendFiles: false, maxContextTokens: 4096, }); const makeNestedSubagentConfig = (id, childIds = []) => ({ ...makeSubagentConfig(id), subagents: { enabled: true, allowSelf: false, agent_ids: childIds }, }); const createViewableAgent = async (id) => { const agent = await createAgent({ id, name: id, provider: 'openai', model: 'gpt-4', author: new mongoose.Types.ObjectId(), tools: [], }); await grantView(agent); return agent; }; it('loads a configured subagent, populates `subagentAgentConfigs`, and keeps it out of `agentConfigs`', async () => { const subAgent = await createAgent({ id: SUBAGENT_ID, name: 'Explicit Subagent', provider: 'openai', model: 'gpt-4', author: new mongoose.Types.ObjectId(), tools: ['web'], }); await grantView(subAgent); const primaryConfig = makePrimaryConfig({ subagents: { enabled: true, allowSelf: true, agent_ids: [SUBAGENT_ID] }, }); const subagentConfig = makeSubagentConfig(SUBAGENT_ID); let call = 0; let subagentConvoFileIds; mockInitializeAgent.mockImplementation(async (params, dbDeps) => { call += 1; if (call === 1) { return primaryConfig; } subagentConvoFileIds = await dbDeps.getConvoFiles(params.conversationId); return subagentConfig; }); await initializeClient({ req: makeSubagentReq(), res: {}, signal: new AbortController().signal, endpointOption: makeEndpointOption(), }); expect(mockInitializeAgent).toHaveBeenCalledTimes(2); const subagentDbDeps = mockInitializeAgent.mock.calls[1][1]; expect(subagentDbDeps.getConvoFiles).toBeInstanceOf(Function); expect(subagentDbDeps.db).toBeUndefined(); expect(subagentConvoFileIds).toEqual([]); /** The subagent's AgentConfig is attached to the primary for run.ts to * turn into `SubagentConfig[]` on the parent's `AgentInputs`. */ expect(agentClientArgs.agent.subagentAgentConfigs).toHaveLength(1); expect(agentClientArgs.agent.subagentAgentConfigs[0].id).toBe(SUBAGENT_ID); /** Subagent-only agents must NOT appear in `agentConfigs` — otherwise the * graph would treat them as a parallel/handoff node. */ expect(agentClientArgs.agentConfigs).toBeDefined(); expect(agentClientArgs.agentConfigs.has(SUBAGENT_ID)).toBe(false); }); it('preserves subagent tool context for ON_TOOL_EXECUTE (Codex P1 regression guard)', async () => { /** Verifies the Codex P1 fix: `agentToolContexts.delete(subagentId)` is * NOT called for subagent-only agents, so when the child dispatches * `ON_TOOL_EXECUTE` the parent can still resolve its tool context * (agent, tool_resources, skill ACLs, actionsEnabled) to run tools * with the right scope. We drive the real `loadTools` closure that * `initializeClient` wires into `toolExecuteOptions`. */ const subAgent = await createAgent({ id: SUBAGENT_ID, name: 'Explicit Subagent', provider: 'openai', model: 'gpt-4', author: new mongoose.Types.ObjectId(), tools: ['web'], }); await grantView(subAgent); const primaryConfig = makePrimaryConfig({ subagents: { enabled: true, allowSelf: false, agent_ids: [SUBAGENT_ID] }, }); const subagentConfig = makeSubagentConfig(SUBAGENT_ID); let call = 0; mockInitializeAgent.mockImplementation(() => Promise.resolve(++call === 1 ? primaryConfig : subagentConfig), ); await initializeClient({ req: makeSubagentReq(), res: {}, signal: new AbortController().signal, endpointOption: makeEndpointOption(), }); expect(capturedToolExecuteOptions?.loadTools).toBeInstanceOf(Function); /** Invoke the real closure with the subagent's id. If `agentToolContexts` * had been deleted (as in the pre-fix code), this would call * `loadToolsForExecution` with `agent: undefined` — actions/resource- * scoped tools would silently drop. */ await capturedToolExecuteOptions.loadTools(['web'], SUBAGENT_ID); expect(mockLoadToolsForExecution).toHaveBeenCalledTimes(1); const arg = mockLoadToolsForExecution.mock.calls[0][0]; expect(arg.agent).toBeDefined(); expect(arg.agent.id).toBe(SUBAGENT_ID); expect(arg.toolRegistry).toBeInstanceOf(Map); expect(arg.tool_resources).toEqual({ file_search: { file_ids: ['file_1'] } }); expect(arg.actionsEnabled).toBe(true); }); it('deduplicates repeated ids in subagents.agent_ids', async () => { const subAgent = await createAgent({ id: DUPLICATE_SUBAGENT_ID, name: 'Dup Subagent', provider: 'openai', model: 'gpt-4', author: new mongoose.Types.ObjectId(), tools: [], }); await grantView(subAgent); const primaryConfig = makePrimaryConfig({ subagents: { enabled: true, allowSelf: false, /** Same id three times — the backend must not load the agent * repeatedly and must not emit three SubagentConfig entries. */ agent_ids: [DUPLICATE_SUBAGENT_ID, DUPLICATE_SUBAGENT_ID, DUPLICATE_SUBAGENT_ID], }, }); const subagentConfig = makeSubagentConfig(DUPLICATE_SUBAGENT_ID); let initCalls = 0; mockInitializeAgent.mockImplementation(() => { initCalls += 1; return Promise.resolve(initCalls === 1 ? primaryConfig : subagentConfig); }); await initializeClient({ req: makeSubagentReq(), res: {}, signal: new AbortController().signal, endpointOption: makeEndpointOption(), }); /** One call for primary, one for the subagent — not four. */ expect(mockInitializeAgent).toHaveBeenCalledTimes(2); expect(agentClientArgs.agent.subagentAgentConfigs).toHaveLength(1); }); it('rejects nested subagent chains deeper than MAX_SUBAGENT_DEPTH', async () => { const ids = Array.from( { length: MAX_SUBAGENT_DEPTH + 1 }, (_, index) => `agent_depth_${index}`, ); for (const id of ids) { await createViewableAgent(id); } const primaryConfig = makePrimaryConfig({ subagents: { enabled: true, allowSelf: false, agent_ids: [ids[0]] }, }); const nestedConfigs = new Map( ids.map((id, index) => [ id, makeNestedSubagentConfig(id, index < ids.length - 1 ? [ids[index + 1]] : []), ]), ); mockInitializeAgent.mockImplementation(({ agent }) => Promise.resolve(agent.id === PRIMARY_ID ? primaryConfig : nestedConfigs.get(agent.id)), ); await expect( initializeClient({ req: makeSubagentReq(), res: {}, signal: new AbortController().signal, endpointOption: makeEndpointOption(), }), ).rejects.toThrow(`maximum depth of ${MAX_SUBAGENT_DEPTH}`); expect(logger.warn).toHaveBeenCalledWith( '[initializeClient] Subagent graph depth limit exceeded', expect.objectContaining({ agentId: `agent_depth_${MAX_SUBAGENT_DEPTH - 1}`, primaryAgentId: PRIMARY_ID, depth: MAX_SUBAGENT_DEPTH, maxSubagentDepth: MAX_SUBAGENT_DEPTH, childCount: 1, }), ); expect(agentClientArgs).toBeUndefined(); }); it('preserves deeper path depth when a handoff root is also a nested subagent', async () => { const chainIds = Array.from( { length: MAX_SUBAGENT_DEPTH }, (_, index) => `agent_overlap_depth_${index}`, ); const allIds = [HANDOFF_AND_SUB_ID, ...chainIds]; for (const id of allIds) { await createViewableAgent(id); } const edges = [{ from: PRIMARY_ID, to: HANDOFF_AND_SUB_ID, edgeType: 'handoff' }]; const primaryConfig = makePrimaryConfig({ edges, subagents: { enabled: true, allowSelf: false, agent_ids: [HANDOFF_AND_SUB_ID] }, }); const nestedConfigs = new Map([ [HANDOFF_AND_SUB_ID, makeNestedSubagentConfig(HANDOFF_AND_SUB_ID, [chainIds[0]])], ...chainIds.map((id, index) => [ id, makeNestedSubagentConfig(id, index < chainIds.length - 1 ? [chainIds[index + 1]] : []), ]), ]); mockInitializeAgent.mockImplementation(({ agent }) => Promise.resolve(agent.id === PRIMARY_ID ? primaryConfig : nestedConfigs.get(agent.id)), ); await expect( initializeClient({ req: makeSubagentReq(), res: {}, signal: new AbortController().signal, endpointOption: makeEndpointOption(), }), ).rejects.toThrow(`maximum depth of ${MAX_SUBAGENT_DEPTH}`); expect(logger.warn).toHaveBeenCalledWith( '[initializeClient] Subagent graph depth limit exceeded', expect.objectContaining({ primaryAgentId: PRIMARY_ID, depth: MAX_SUBAGENT_DEPTH, maxSubagentDepth: MAX_SUBAGENT_DEPTH, childCount: 1, }), ); expect(agentClientArgs).toBeUndefined(); }); it('rejects subagent graphs that exceed MAX_SUBAGENT_GRAPH_NODES unique agents', async () => { const firstLevelIds = Array.from({ length: 10 }, (_, index) => `agent_graph_${index}`); const secondLevelIdsByParent = new Map( firstLevelIds.map((id) => [ id, Array.from({ length: 5 }, (_, index) => `${id}_child_${index}`), ]), ); const allIds = [...firstLevelIds, ...Array.from(secondLevelIdsByParent.values()).flat()]; for (const id of allIds) { await createViewableAgent(id); } const primaryConfig = makePrimaryConfig({ subagents: { enabled: true, allowSelf: false, agent_ids: firstLevelIds }, }); const nestedConfigs = new Map( firstLevelIds.map((id) => [id, makeNestedSubagentConfig(id, secondLevelIdsByParent.get(id))]), ); for (const id of Array.from(secondLevelIdsByParent.values()).flat()) { nestedConfigs.set(id, makeNestedSubagentConfig(id)); } mockInitializeAgent.mockImplementation(({ agent }) => Promise.resolve(agent.id === PRIMARY_ID ? primaryConfig : nestedConfigs.get(agent.id)), ); await expect( initializeClient({ req: makeSubagentReq(), res: {}, signal: new AbortController().signal, endpointOption: makeEndpointOption(), }), ).rejects.toThrow(`maximum of ${MAX_SUBAGENT_GRAPH_NODES} unique agents`); expect(logger.warn).toHaveBeenCalledWith( '[initializeClient] Subagent graph node limit exceeded', expect.objectContaining({ primaryAgentId: PRIMARY_ID, loadedSubagentCount: MAX_SUBAGENT_GRAPH_NODES, maxSubagentGraphNodes: MAX_SUBAGENT_GRAPH_NODES, }), ); expect(agentClientArgs).toBeUndefined(); }); it('keeps an agent in `agentConfigs` when it is BOTH a handoff target and a subagent', async () => { /** Overlap case: the same child is used both via handoff edges (needs to * be in agentConfigs) and as a subagent (needs to be in * subagentAgentConfigs, and its tool context preserved). The pipeline * shouldn't silently drop it from the handoff map. */ const shared = await createAgent({ id: HANDOFF_AND_SUB_ID, name: 'Shared Agent', provider: 'openai', model: 'gpt-4', author: new mongoose.Types.ObjectId(), tools: [], }); await grantView(shared); const edges = [{ from: PRIMARY_ID, to: HANDOFF_AND_SUB_ID, edgeType: 'handoff' }]; const primaryConfig = makePrimaryConfig({ edges, subagents: { enabled: true, allowSelf: false, agent_ids: [HANDOFF_AND_SUB_ID], }, }); const sharedConfig = makeSubagentConfig(HANDOFF_AND_SUB_ID); let call = 0; mockInitializeAgent.mockImplementation(() => Promise.resolve(++call === 1 ? primaryConfig : sharedConfig), ); await initializeClient({ req: makeSubagentReq(), res: {}, signal: new AbortController().signal, endpointOption: makeEndpointOption(), }); expect(agentClientArgs.agent.subagentAgentConfigs).toHaveLength(1); /** Shared agent must stay in agentConfigs — it's still the handoff target. */ expect(agentClientArgs.agentConfigs.has(HANDOFF_AND_SUB_ID)).toBe(true); }); it('clears subagents config on primary when the capability is disabled', async () => { /** Admin can turn subagents off at the endpoint level even if an agent was * configured for them. The primary's `subagents` field should be * suppressed so run.ts never builds a SubagentConfig. */ const primaryConfig = makePrimaryConfig({ subagents: { enabled: true, allowSelf: true, agent_ids: [] }, }); mockInitializeAgent.mockResolvedValue(primaryConfig); const req = makeSubagentReq(); /** Remove the capability from the admin config. */ req.config.endpoints.agents.capabilities = []; await initializeClient({ req, res: {}, signal: new AbortController().signal, endpointOption: makeEndpointOption(), }); expect(agentClientArgs.agent.subagents).toBeUndefined(); expect(agentClientArgs.agent.subagentAgentConfigs).toEqual([]); }); it('clears subagents on handoff agents too when capability is disabled (Codex P2 regression)', async () => { /** Codex P2: the capability gate must suppress `subagents` on EVERY * loaded config, not just the primary. `run.ts` iterates all agents * and calls `buildSubagentConfigs` per agent, so a handoff target * with `subagents.enabled: true` persisted on its document would * otherwise still expose self-spawn even when the admin has disabled * the capability globally. */ const authorized = await createAgent({ id: AUTHORIZED_ID, name: 'Handoff Agent', provider: 'openai', model: 'gpt-4', author: new mongoose.Types.ObjectId(), tools: [], }); await grantView(authorized); const edges = [{ from: PRIMARY_ID, to: AUTHORIZED_ID, edgeType: 'handoff' }]; const primaryConfig = makePrimaryConfig({ edges, subagents: { enabled: true, allowSelf: true, agent_ids: [] }, }); const handoffConfig = { id: AUTHORIZED_ID, endpoint: 'agents', edges: [], toolDefinitions: [], toolRegistry: new Map(), userMCPAuthMap: null, tool_resources: {}, /** Handoff agent document has subagents enabled of its own accord. */ subagents: { enabled: true, allowSelf: true, agent_ids: [] }, }; let callCount = 0; mockInitializeAgent.mockImplementation(() => Promise.resolve(++callCount === 1 ? primaryConfig : handoffConfig), ); const req = makeSubagentReq(); /** Capability OFF at endpoint level. */ req.config.endpoints.agents.capabilities = []; await initializeClient({ req, res: {}, signal: new AbortController().signal, endpointOption: makeEndpointOption(), }); /** Primary cleared. */ expect(agentClientArgs.agent.subagents).toBeUndefined(); /** Handoff target must ALSO be cleared — otherwise its self-spawn * would still fire when run.ts iterates agentConfigs. */ const handoffLoaded = agentClientArgs.agentConfigs.get(AUTHORIZED_ID); expect(handoffLoaded).toBeDefined(); expect(handoffLoaded.subagents).toBeUndefined(); expect(handoffLoaded.subagentAgentConfigs).toBeUndefined(); }); it('skips subagent loading entirely when the feature is disabled on the agent', async () => { const primaryConfig = makePrimaryConfig({ subagents: { enabled: false, allowSelf: true, agent_ids: [SUBAGENT_ID] }, }); mockInitializeAgent.mockResolvedValue(primaryConfig); await initializeClient({ req: makeSubagentReq(), res: {}, signal: new AbortController().signal, endpointOption: makeEndpointOption(), }); /** Only one initializeAgent call — for the primary. No subagent loaded. */ expect(mockInitializeAgent).toHaveBeenCalledTimes(1); expect(agentClientArgs.agent.subagentAgentConfigs).toEqual([]); }); });