Skip to content

fix: use session-pinned agent in RunStream instead of shared currentAgent#2009

Open
dgageot wants to merge 1 commit intodocker:mainfrom
dgageot:board/fix-sub-agents-da8bbb08
Open

fix: use session-pinned agent in RunStream instead of shared currentAgent#2009
dgageot wants to merge 1 commit intodocker:mainfrom
dgageot:board/fix-sub-agents-da8bbb08

Conversation

@dgageot
Copy link
Member

@dgageot dgageot commented Mar 9, 2026

Problem

Sub-agents dispatched via run_background_agent executed with root's toolset, model, and instructions. This happened because RunStream resolved the agent through the shared currentAgent field, which is never updated for background sessions.

Root Cause

Multiple places in the streaming loop (RunStream, processToolCalls, finalizeEventChannel, Summarize, and helper methods) independently called r.CurrentAgent() or r.CurrentAgentName(), which always returns the root agent for background sessions since run_background_agent never calls setCurrentAgent.

Fix

Introduce resolveSessionAgent(sess) — a single method that checks sess.AgentName first (set for background agent tasks) and falls back to CurrentAgent() for interactive sessions. This is used consistently across all affected call sites.

Additional fixes

  • Nil-pointer panic: The previous inline resolution silently discarded the error from team.Agent() and could leave the agent nil. The new helper always falls back to CurrentAgent().
  • Pre-loop event emissions: TeamInfo and ToolsetInfo events before the loop used r.CurrentAgentName() instead of the resolved agent.
  • emitAgentWarnings / configureToolsetHandlers: These methods already received the agent as a parameter but independently called r.CurrentAgentName() for event names.
  • Summarize: Used r.CurrentAgentName() and r.CurrentAgent() instead of the session-aware resolution.

Assisted-By: docker-agent

@dgageot dgageot requested a review from a team as a code owner March 9, 2026 16:33
Copy link

@docker-agent docker-agent bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

Assessment: 🟢 APPROVE

This PR correctly fixes a critical bug where background sub-agents were using the root agent's configuration instead of their own. The implementation is sound:

resolveSessionAgent(sess) implementation is correct

  • Properly checks sess.AgentName first for background agent tasks
  • Safely handles errors from team.Agent() by falling back to CurrentAgent()
  • Returns a non-nil agent in all cases

All call sites correctly updated

  • RunStream: Uses resolved agent consistently throughout the loop
  • processToolCalls: Now uses session-pinned agent
  • finalizeEventChannel: Correctly resolves agent for StreamStopped event
  • Summarize: Properly resolves agent for compaction events
  • configureToolsetHandlers & emitAgentWarnings: Now use the passed agent parameter instead of independently calling CurrentAgent()

Eliminates race condition

  • Background agent sessions no longer race on the shared currentAgent field
  • Each session consistently uses its pinned agent throughout its lifecycle

Nil-pointer safety improved

  • Previous inline code silently discarded errors from team.Agent() which could theoretically leave agent nil
  • New helper always returns a valid agent

Findings

No issues identified in the changed code. The refactoring is clean, the fix addresses the root cause, and the implementation handles edge cases correctly.

…gent

Sub-agents dispatched via run_background_agent executed with root's
toolset, model, and instructions because RunStream resolved the agent
through the shared currentAgent field, which is never updated for
background sessions.

Introduce resolveSessionAgent(sess) that checks sess.AgentName first
(set for background agent tasks) and falls back to CurrentAgent() for
interactive sessions. Use it consistently in RunStream, processToolCalls,
finalizeEventChannel, Summarize, and helper methods that already receive
the agent but were independently calling CurrentAgentName().

This also fixes a potential nil-pointer panic: the previous inline
resolution silently discarded the error from team.Agent() and could
leave the agent nil.

Assisted-By: docker-agent
@dgageot dgageot force-pushed the board/fix-sub-agents-da8bbb08 branch from ea307ba to 74ed11c Compare March 9, 2026 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant