mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-10-21 17:44:11 +00:00
🧶 fix: Untangle Parallel Subagent Descriptor Paths (#15492)
* fix: isolate parallel subagent descriptor walks * fix: preserve canonical subagent config identity * fix: separate subagent graph assembly from path validation
This commit is contained in:
parent
6d56d3b6fe
commit
6372cb08ee
3 changed files with 111 additions and 7 deletions
|
|
@ -1199,13 +1199,10 @@ const initializeClient = async ({
|
|||
subagentGraphIds.add(subagentId);
|
||||
}
|
||||
countExpandedSubagentDescriptor(subagentId);
|
||||
const existingChildren = await buildLazySubagentDescriptors(
|
||||
existing,
|
||||
depth + 1,
|
||||
nextAncestors,
|
||||
);
|
||||
existing.lazySubagentConfigs = existingChildren.filter((child) => child.configId);
|
||||
existing.subagentAgentConfigs = existingChildren.filter((child) => !child.configId);
|
||||
/** Every initialized config is expanded independently in `rootSubagentConfigs`.
|
||||
* Descend here only to enforce path-sensitive depth and size limits; mutating the
|
||||
* shared object from this ancestor-specific walk would race its root expansion. */
|
||||
await buildLazySubagentDescriptors(existing, depth + 1, nextAncestors);
|
||||
return existing;
|
||||
}
|
||||
const metadata = await loadSubagentMetadata(subagentId);
|
||||
|
|
|
|||
|
|
@ -2479,6 +2479,45 @@ describe('initializeClient — subagent loading', () => {
|
|||
expect(agentClientArgs.agentConfigs.has(HANDOFF_AND_SUB_ID)).toBe(true);
|
||||
});
|
||||
|
||||
it('preserves shared initialized agent children across parallel walkers', async () => {
|
||||
const leftId = 'agent_parallel_left';
|
||||
const rightId = 'agent_parallel_right';
|
||||
const sharedId = 'agent_parallel_shared';
|
||||
const primaryConfig = makePrimaryConfig({
|
||||
subagents: { enabled: true, allowSelf: false, agent_ids: [leftId, rightId] },
|
||||
});
|
||||
const leftConfig = makeNestedSubagentConfig(leftId, [sharedId]);
|
||||
const rightConfig = makeNestedSubagentConfig(rightId, [sharedId]);
|
||||
const sharedConfig = makeNestedSubagentConfig(sharedId, [leftId]);
|
||||
mockInitializeAgent.mockResolvedValue(primaryConfig);
|
||||
processAddedConvo.mockImplementationOnce(async ({ agentConfigs }) => {
|
||||
agentConfigs.set(leftId, leftConfig);
|
||||
agentConfigs.set(rightId, rightConfig);
|
||||
agentConfigs.set(sharedId, sharedConfig);
|
||||
return { userMCPAuthMap: undefined };
|
||||
});
|
||||
|
||||
await initializeClient({
|
||||
req: makeSubagentReq(),
|
||||
res: {},
|
||||
signal: new AbortController().signal,
|
||||
endpointOption: makeEndpointOption(),
|
||||
});
|
||||
|
||||
const subagentsById = new Map(
|
||||
agentClientArgs.agent.subagentAgentConfigs.map((config) => [config.id, config]),
|
||||
);
|
||||
const left = subagentsById.get(leftId);
|
||||
const right = subagentsById.get(rightId);
|
||||
const leftShared = left.subagentAgentConfigs[0];
|
||||
const rightShared = right.subagentAgentConfigs[0];
|
||||
expect(leftShared).toBe(sharedConfig);
|
||||
expect(rightShared).toBe(sharedConfig);
|
||||
expect(leftShared.subagentAgentConfigs.map((child) => child.id)).toEqual([leftId]);
|
||||
expect(rightShared.subagentAgentConfigs.map((child) => child.id)).toEqual([leftId]);
|
||||
expect(agentClientArgs.agentConfigs.get(sharedId)).toBe(sharedConfig);
|
||||
});
|
||||
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue