Skip to content

Commit 1bc5725

Browse files
fix for agent multiple times calling
1 parent 124fcf7 commit 1bc5725

4 files changed

Lines changed: 54 additions & 19 deletions

File tree

src/backend/v4/magentic_agents/foundry_agent.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,12 @@ async def _create_azure_search_enabled_client(self, chatClient=None) -> Optional
185185
"Always use the Azure AI Search tool and configured index for knowledge retrieval."
186186
)
187187

188-
print(f"[DEBUG] Creating agent '{self.agent_name}' with instructions (first 200 chars): {enhanced_instructions[:200]}...")
189-
print(f"[DEBUG] Agent model: {self.model_deployment_name}")
190-
print(f"[DEBUG] Search config: connection={connection_name}, index={index_name}, query_type={query_type}, top_k={top_k}")
188+
print(f"[AGENT CREATE] 🆕 Creating agent in Foundry: '{self.agent_name}'", flush=True)
189+
print(f"[AGENT CREATE] Model: {self.model_deployment_name}", flush=True)
190+
print(f"[AGENT CREATE] Search: connection={connection_name}, index={index_name}", flush=True)
191191

192192
azure_agent = await self.project_client.agents.create_version(
193-
agent_name=self.agent_name,
193+
agent_name=self.agent_name, # Use original name
194194
definition=PromptAgentDefinition(
195195
model=self.model_deployment_name,
196196
instructions=enhanced_instructions,
@@ -213,19 +213,13 @@ async def _create_azure_search_enabled_client(self, chatClient=None) -> Optional
213213

214214
self._azure_server_agent_id = azure_agent.id
215215
self._azure_server_agent_version = azure_agent.version
216+
print(f"[AGENT CREATE] ✅ Created agent: name={azure_agent.name}, id={azure_agent.id}, version={azure_agent.version}", flush=True)
216217
self.logger.info(
217-
"Created Azure AI Search agent via create_version (name=%s, id=%s, version=%s, connection=%s, index=%s, query_type=%s, top_k=%s).",
218+
"Created Azure AI Search agent via create_version (name=%s, id=%s, version=%s).",
218219
azure_agent.name,
219220
azure_agent.id,
220221
azure_agent.version,
221-
connection_name,
222-
index_name,
223-
query_type,
224-
top_k,
225222
)
226-
print(f"[DEBUG] Created agent via create_version: name={azure_agent.name}, id={azure_agent.id}, version={azure_agent.version}")
227-
print(f"[DEBUG] Agent definition: {azure_agent.definition}")
228-
print(f"[DEBUG] Agent instructions from definition: {getattr(azure_agent.definition, 'instructions', 'N/A')}")
229223

230224
# Wrap in AzureAIClient using agent_name and agent_version (NOT agent_id)
231225
# AzureAIClient constructor: agent_name, agent_version, project_endpoint, credential

src/backend/v4/magentic_agents/magentic_agent_factory.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ async def create_agent_from_config(
115115
index_name,
116116
"Reasoning" if use_reasoning else "Foundry",
117117
)
118+
print(f"[FACTORY] 🆕 Creating NEW agent: {agent_obj.name} (id={id(agent_obj)})", flush=True)
118119

119120
agent = FoundryAgentTemplate(
120121
agent_name=agent_obj.name,

src/backend/v4/orchestration/human_approval_manager.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class HumanApprovalMagenticManager(StandardMagenticManager):
3333
approval_enabled: bool = True
3434
magentic_plan: Optional[MPlan] = None
3535
current_user_id: str # populated in __init__
36+
_called_agents: set # Track which agents have been called
3637

3738
def __init__(self, user_id: str, agent, *args, **kwargs):
3839
"""
@@ -43,6 +44,9 @@ def __init__(self, user_id: str, agent, *args, **kwargs):
4344
*args: Additional positional arguments for the parent StandardMagenticManager.
4445
**kwargs: Additional keyword arguments for the parent StandardMagenticManager.
4546
"""
47+
48+
# Initialize called agents tracker
49+
self._called_agents = set()
4650

4751
plan_append = """
4852
@@ -55,13 +59,23 @@ def __init__(self, user_id: str, agent, *args, **kwargs):
5559
to be taken. If a step involves multiple actions, separate them into distinct steps with an agent included in each step.
5660
If the step is taken by an agent that is not part of the team, such as the MagenticManager, please always list the MagenticManager as the agent for that step. At any time, if more information is needed from the user, use the ProxyAgent to request this information.
5761
62+
CRITICAL: Each agent should only be called ONCE to perform their task. Do NOT call the same agent multiple times.
63+
After an agent has provided their response, move on to the next agent in the plan.
64+
5865
Here is an example of a well-structured plan:
5966
- **EnhancedResearchAgent** to gather authoritative data on the latest industry trends and best practices in employee onboarding
6067
- **EnhancedResearchAgent** to gather authoritative data on Innovative onboarding techniques that enhance new hire engagement and retention.
6168
- **DocumentCreationAgent** to draft a comprehensive onboarding plan that includes a detailed schedule of onboarding activities and milestones.
6269
- **DocumentCreationAgent** to draft a comprehensive onboarding plan that includes a checklist of resources and materials needed for effective onboarding.
6370
- **ProxyAgent** to review the drafted onboarding plan for clarity and completeness.
6471
- **MagenticManager** to finalize the onboarding plan and prepare it for presentation to stakeholders.
72+
"""
73+
74+
# Add progress ledger prompt to prevent re-calling agents
75+
progress_append = """
76+
CRITICAL RULE: DO NOT call the same agent more than once unless absolutely necessary.
77+
If an agent has already provided a response, consider their task COMPLETE and move to the next agent.
78+
Only re-call an agent if their previous response was explicitly an error or failure.
6579
"""
6680

6781
final_append = """
@@ -75,6 +89,10 @@ def __init__(self, user_id: str, agent, *args, **kwargs):
7589
ORCHESTRATOR_TASK_LEDGER_PLAN_UPDATE_PROMPT + plan_append
7690
)
7791
kwargs["final_answer_prompt"] = ORCHESTRATOR_FINAL_ANSWER_PROMPT + final_append
92+
93+
# Override progress ledger prompt to discourage re-calling agents
94+
from agent_framework._workflows._magentic import ORCHESTRATOR_PROGRESS_LEDGER_PROMPT
95+
kwargs["progress_ledger_prompt"] = ORCHESTRATOR_PROGRESS_LEDGER_PROMPT + progress_append
7896

7997
self.current_user_id = user_id
8098
# New API: StandardMagenticManager takes agent as first positional argument
@@ -305,4 +323,4 @@ def plan_to_obj(self, magentic_context: MagenticContext, ledger) -> MPlan:
305323
task=task_text,
306324
)
307325

308-
return return_plan
326+
return return_plan

src/backend/v4/orchestration/orchestration_manager.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,17 +197,19 @@ async def init_orchestration(
197197
# Assemble workflow with callback
198198
storage = InMemoryCheckpointStorage()
199199

200-
# New API: .participants() accepts a list of agents
200+
# New SDK: participants() accepts a Sequence (list) of agents
201+
# The orchestrator uses agent.name to identify them
201202
participant_list = list(participants.values())
203+
cls.logger.info("Participants for workflow: %s", list(participants.keys()))
204+
print(f"[DEBUG] Participants for workflow: {list(participants.keys())}", flush=True)
202205

203206
builder = (
204207
MagenticBuilder()
205-
.participants(participant_list)
208+
.participants(participant_list) # New SDK: pass as list
206209
.with_manager(
207210
manager=manager, # Pass manager instance (extends StandardMagenticManager)
208211
max_round_count=orchestration_config.max_rounds,
209-
max_stall_count=3,
210-
max_reset_count=2,
212+
max_stall_count=0, # CRITICAL: Prevent re-calling agents when stalled (default is 3!)
211213
)
212214
.with_checkpointing(storage)
213215
)
@@ -381,12 +383,16 @@ async def run_orchestration(self, user_id: str, input_task) -> None:
381383
task_text = getattr(input_task, "description", str(input_task))
382384
self.logger.debug("Task: %s", task_text)
383385

386+
# Track how many times each agent is called (for debugging duplicate calls)
387+
agent_call_counts: dict = {}
388+
384389
try:
385390
# Execute workflow using run_stream with task as positional parameter
386391
# The execution settings are configured in the manager/client
387392
final_output: str | None = None
388393

389394
self.logger.info("Starting workflow execution...")
395+
print(f"[ORCHESTRATOR] 🚀 Starting workflow with max_rounds={orchestration_config.max_rounds}", flush=True)
390396
last_message_id: str | None = None
391397
async for event in workflow.run_stream(task_text):
392398
try:
@@ -431,11 +437,20 @@ async def run_orchestration(self, user_id: str, input_task) -> None:
431437

432438
# Handle group chat request sent
433439
elif isinstance(event, GroupChatRequestSentEvent):
440+
agent_name = event.participant_name
441+
agent_call_counts[agent_name] = agent_call_counts.get(agent_name, 0) + 1
442+
call_num = agent_call_counts[agent_name]
443+
434444
self.logger.info(
435-
"[REQUEST SENT (round %d)] to agent: %s",
445+
"[REQUEST SENT (round %d)] to agent: %s (call #%d)",
436446
event.round_index,
437-
event.participant_name
447+
agent_name,
448+
call_num
438449
)
450+
print(f"[ORCHESTRATOR] 📤 REQUEST SENT round={event.round_index} to agent={agent_name} (call #{call_num})", flush=True)
451+
452+
if call_num > 1:
453+
print(f"[ORCHESTRATOR] ⚠️ WARNING: Agent '{agent_name}' called {call_num} times!", flush=True)
439454

440455
# Handle group chat response received - THIS IS WHERE AGENT RESPONSES COME
441456
elif isinstance(event, GroupChatResponseReceivedEvent):
@@ -496,6 +511,13 @@ async def run_orchestration(self, user_id: str, input_task) -> None:
496511
# Extract final result
497512
final_text = final_output if final_output else ""
498513

514+
# Log agent call summary
515+
print(f"\n[ORCHESTRATOR] 📊 AGENT CALL SUMMARY:", flush=True)
516+
for agent_name, count in agent_call_counts.items():
517+
status = "✅" if count == 1 else "⚠️ DUPLICATE"
518+
print(f" {status} {agent_name}: called {count} time(s)", flush=True)
519+
self.logger.info("Agent call counts: %s", agent_call_counts)
520+
499521
# Log results
500522
self.logger.info("\nAgent responses:")
501523
self.logger.info(

0 commit comments

Comments
 (0)