From e54440b7d19f88302f36f81acde546df9ebdfcf1 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Sat, 18 Apr 2026 12:07:22 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=81=20fix:=20don't=20seed=20initialize?= =?UTF-8?q?.js=20agentConfigs=20from=20the=20pre-pruning=20callback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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`. --- .../services/Endpoints/agents/initialize.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/api/server/services/Endpoints/agents/initialize.js b/api/server/services/Endpoints/agents/initialize.js index 0a329dea0e..c8515bd0fa 100644 --- a/api/server/services/Endpoints/agents/initialize.js +++ b/api/server/services/Endpoints/agents/initialize.js @@ -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;