🔁 fix: don't seed initialize.js agentConfigs from the pre-pruning callback

Addresses the fifth P1 codex finding on #12740: `onAgentInitialized`
fires during BFS, BEFORE the helper prunes agents that become
disconnected once `filterOrphanedEdges` runs. Writing the sub-agent
straight into the outer `agentConfigs` there and then only additively
merging the pruned `discoveredConfigs` left stranded entries in the
outer map, and `AgentClient` would still hand them to `createRun` as
extra parallel start nodes (the exact failure mode the pass-4 prune
was meant to eliminate for the API controllers).

Drop the `agentConfigs.set` from the callback and replace the additive
merge with a direct copy from `discoveredConfigs`, which is now the
single authoritative source of what the run should see. The
per-agent tool context map is still populated during BFS — stale
entries there are harmless because they're only read by closure inside
`ON_TOOL_EXECUTE` and are unreachable once the agent is not in
`agentConfigs`.
This commit is contained in:
Danny Avila 2026-04-18 12:07:22 -04:00
parent 4cbfffc9ee
commit e54440b7d1

View file

@ -260,8 +260,13 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
getCodeGeneratedFiles: db.getCodeGeneratedFiles,
filterFilesByAgentAccess,
},
// The callback fires during BFS, before the helper prunes agents
// whose edges end up filtered. Don't populate `agentConfigs` here —
// `discoveredConfigs` (returned below) is the authoritative pruned
// set. The per-agent tool context map is OK to keep populated even
// for pruned ids: it's only read by closure in ON_TOOL_EXECUTE,
// stale entries are unreachable at runtime.
onAgentInitialized: (agentId, agent, config) => {
agentConfigs.set(agentId, config);
agentToolContexts.set(agentId, {
agent,
toolRegistry: config.toolRegistry,
@ -277,12 +282,12 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
},
);
// Merge any entries the onAgentInitialized callback did not receive
// (defensive: discoverConnectedAgents already returns a canonical map)
// Copy the pruned discovery result into the outer map. Anything the
// helper dropped (skipped or unreachable after edge filtering) is
// intentionally absent. `processAddedConvo` below may still add more
// entries for parallel multi-convo execution.
for (const [agentId, config] of discoveredConfigs) {
if (!agentConfigs.has(agentId)) {
agentConfigs.set(agentId, config);
}
agentConfigs.set(agentId, config);
}
let userMCPAuthMap = discoveredMCPAuthMap;