Skip to content

fix: preserve system message during multi-function registration in AgentBuilder#7326

Open
roli-lpci wants to merge 1 commit intomicrosoft:0.2from
roli-lpci:fix/agent-builder-system-message-overwrite-5037
Open

fix: preserve system message during multi-function registration in AgentBuilder#7326
roli-lpci wants to merge 1 commit intomicrosoft:0.2from
roli-lpci:fix/agent-builder-system-message-overwrite-5037

Conversation

@roli-lpci
Copy link
Copy Markdown

Summary

Fixes #5037.

When AgentBuilder._build_agents() registers multiple functions to a single agent, the system message is overwritten on each iteration rather than accumulated. The loop reads from the static agent_configs dict (which holds the raw LLM-generated config and never mutates) instead of the live agent's .system_message property (which reflects prior update_system_message() calls).

Result: After registering N functions, the agent's system message contains only the last function's description. All prior function descriptions are lost, and the GROUP_CHAT_DESCRIPTION wrapper — including TERMINATE instructions — is destroyed.

Root cause

# Before (line 759): reads from STATIC config — always returns original raw message
agents_current_system_message = [
    agent["system_message"] for agent in agent_configs if agent["name"] == perferred_agent_name
][0]
# After: reads from LIVE agent — reflects all prior update_system_message() calls
preferred_agent.system_message

What the fix preserves

  • All function descriptions across loop iterations
  • GROUP_CHAT_DESCRIPTION wrapper (TERMINATE instruction, group chat context, member list)
  • CODING_AND_TASK_SKILL_INSTRUCTION block

Also extracts preferred_agent as a local variable, eliminating 3 repeated self.agent_procs_assign[perferred_agent_name][0] lookups.

Test plan

  • New regression test test_multi_function_system_message_preserved() — exercises actual _build_agents() with 3 functions assigned to one agent. 9 assertions verify all function names, descriptions, TERMINATE instruction, and GROUP_CHAT_DESCRIPTION structure are preserved. Runs without API keys (mocks config_list_from_json and builder_model.create).
  • Result: 1 passed, 7 skipped (skipped tests are OpenAI-gated integration tests)
  • Existing tests unaffected

🤖 Generated with Claude Code

…ration (microsoft#5037)

AgentBuilder._build_agents() reads the system message from the static
agent_configs dict on each loop iteration. Because agent_configs never
mutates (it holds the raw LLM-generated config), each iteration
overwrites the live agent's system message with only the latest
function — destroying all previously registered function descriptions
and the GROUP_CHAT_DESCRIPTION wrapper (including TERMINATE instructions).

The fix reads from the live agent's .system_message property instead,
which reflects all prior update_system_message() calls. This preserves:
- All function descriptions across iterations
- GROUP_CHAT_DESCRIPTION wrapper (TERMINATE, group chat context)
- CODING_AND_TASK_SKILL_INSTRUCTION block

Also extracts a local variable to eliminate 3 repeated dict lookups.

Includes a regression test that exercises the actual _build_agents()
code path with 3 functions assigned to one agent, verifying all
descriptions and TERMINATE instruction survive. Runs without API keys.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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