Skip to content

Commit c609b14

Browse files
alliscodealliscodemoonbox3
authored
Python: Fix GroupChat orchestrator message cleanup issue (#3712)
* Fix GroupChat orchestrator message cleanup issue Apply clean_conversation_for_handoff to GroupChatOrchestrator and AgentBasedGroupChatOrchestrator _handle_response methods to remove tool-related content that causes API errors from empty messages. Fixes #3705 * Move orchestration related files to orchestrations package. * Fix imports --------- Co-authored-by: alliscode <bentho@microsoft.com> Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
1 parent f96772f commit c609b14

20 files changed

Lines changed: 131 additions & 174 deletions

python/packages/core/agent_framework/_workflows/__init__.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,6 @@
77
AgentExecutorResponse,
88
)
99
from ._agent_utils import resolve_agent_id
10-
from ._base_group_chat_orchestrator import (
11-
BaseGroupChatOrchestrator,
12-
GroupChatRequestMessage,
13-
GroupChatRequestSentEvent,
14-
GroupChatResponseReceivedEvent,
15-
)
1610
from ._checkpoint import (
1711
CheckpointStorage,
1812
FileCheckpointStorage,
@@ -65,8 +59,6 @@
6559
handler,
6660
)
6761
from ._function_executor import FunctionExecutor, executor
68-
from ._orchestration_request_info import AgentRequestInfoResponse
69-
from ._orchestration_state import OrchestrationState
7062
from ._request_info_mixin import response_handler
7163
from ._runner import Runner
7264
from ._runner_context import (
@@ -97,8 +89,6 @@
9789
"AgentExecutor",
9890
"AgentExecutorRequest",
9991
"AgentExecutorResponse",
100-
"AgentRequestInfoResponse",
101-
"BaseGroupChatOrchestrator",
10292
"Case",
10393
"CheckpointStorage",
10494
"Default",
@@ -115,13 +105,9 @@
115105
"FileCheckpointStorage",
116106
"FunctionExecutor",
117107
"GraphConnectivityError",
118-
"GroupChatRequestMessage",
119-
"GroupChatRequestSentEvent",
120-
"GroupChatResponseReceivedEvent",
121108
"InMemoryCheckpointStorage",
122109
"InProcRunnerContext",
123110
"Message",
124-
"OrchestrationState",
125111
"RequestInfoEvent",
126112
"Runner",
127113
"RunnerContext",

python/packages/core/agent_framework/orchestrations/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@
1717
"HandoffBuilder",
1818
"HandoffConfiguration",
1919
"HandoffSentEvent",
20+
# Base orchestrator
21+
"BaseGroupChatOrchestrator",
22+
"GroupChatRequestMessage",
23+
"GroupChatRequestSentEvent",
24+
"GroupChatResponseReceivedEvent",
25+
"TerminationCondition",
26+
# Orchestration helpers
27+
"AgentRequestInfoResponse",
28+
"OrchestrationState",
29+
"clean_conversation_for_handoff",
30+
"create_completion_message",
2031
# Group Chat
2132
"AgentBasedGroupChatOrchestrator",
2233
"AgentOrchestrationOutput",

python/packages/core/agent_framework/orchestrations/__init__.pyi

Lines changed: 34 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,39 @@
11
# Copyright (c) Microsoft. All rights reserved.
22

3-
# Type stubs for lazy-loaded orchestrations module
4-
# These re-export types from agent_framework_orchestrations
5-
6-
from agent_framework_orchestrations import (
7-
# Magentic
8-
MAGENTIC_MANAGER_NAME as MAGENTIC_MANAGER_NAME,
9-
)
10-
from agent_framework_orchestrations import (
11-
ORCH_MSG_KIND_INSTRUCTION as ORCH_MSG_KIND_INSTRUCTION,
12-
)
13-
from agent_framework_orchestrations import (
14-
ORCH_MSG_KIND_NOTICE as ORCH_MSG_KIND_NOTICE,
15-
)
16-
from agent_framework_orchestrations import (
17-
ORCH_MSG_KIND_TASK_LEDGER as ORCH_MSG_KIND_TASK_LEDGER,
18-
)
19-
from agent_framework_orchestrations import (
20-
ORCH_MSG_KIND_USER_TASK as ORCH_MSG_KIND_USER_TASK,
21-
)
22-
from agent_framework_orchestrations import (
23-
# Group Chat
24-
AgentBasedGroupChatOrchestrator as AgentBasedGroupChatOrchestrator,
25-
)
26-
from agent_framework_orchestrations import (
27-
AgentOrchestrationOutput as AgentOrchestrationOutput,
28-
)
29-
from agent_framework_orchestrations import (
30-
# Concurrent
31-
ConcurrentBuilder as ConcurrentBuilder,
32-
)
33-
from agent_framework_orchestrations import (
34-
GroupChatBuilder as GroupChatBuilder,
35-
)
36-
from agent_framework_orchestrations import (
37-
GroupChatOrchestrator as GroupChatOrchestrator,
38-
)
39-
from agent_framework_orchestrations import (
40-
GroupChatSelectionFunction as GroupChatSelectionFunction,
41-
)
42-
from agent_framework_orchestrations import (
43-
GroupChatState as GroupChatState,
44-
)
45-
from agent_framework_orchestrations import (
46-
# Handoff
47-
HandoffAgentExecutor as HandoffAgentExecutor,
48-
)
49-
from agent_framework_orchestrations import (
50-
HandoffAgentUserRequest as HandoffAgentUserRequest,
51-
)
52-
from agent_framework_orchestrations import (
53-
HandoffBuilder as HandoffBuilder,
54-
)
55-
from agent_framework_orchestrations import (
56-
HandoffConfiguration as HandoffConfiguration,
57-
)
58-
from agent_framework_orchestrations import (
59-
HandoffSentEvent as HandoffSentEvent,
60-
)
61-
from agent_framework_orchestrations import (
62-
MagenticAgentExecutor as MagenticAgentExecutor,
63-
)
64-
from agent_framework_orchestrations import (
65-
MagenticBuilder as MagenticBuilder,
66-
)
67-
from agent_framework_orchestrations import (
68-
MagenticContext as MagenticContext,
69-
)
70-
from agent_framework_orchestrations import (
71-
MagenticManagerBase as MagenticManagerBase,
72-
)
73-
from agent_framework_orchestrations import (
74-
MagenticOrchestrator as MagenticOrchestrator,
75-
)
76-
from agent_framework_orchestrations import (
77-
MagenticOrchestratorEvent as MagenticOrchestratorEvent,
78-
)
79-
from agent_framework_orchestrations import (
80-
MagenticOrchestratorEventType as MagenticOrchestratorEventType,
81-
)
82-
from agent_framework_orchestrations import (
83-
MagenticPlanReviewRequest as MagenticPlanReviewRequest,
84-
)
85-
from agent_framework_orchestrations import (
86-
MagenticPlanReviewResponse as MagenticPlanReviewResponse,
87-
)
88-
from agent_framework_orchestrations import (
89-
MagenticProgressLedger as MagenticProgressLedger,
90-
)
91-
from agent_framework_orchestrations import (
92-
MagenticProgressLedgerItem as MagenticProgressLedgerItem,
93-
)
94-
from agent_framework_orchestrations import (
95-
MagenticResetSignal as MagenticResetSignal,
96-
)
97-
from agent_framework_orchestrations import (
98-
# Sequential
99-
SequentialBuilder as SequentialBuilder,
100-
)
101-
from agent_framework_orchestrations import (
102-
StandardMagenticManager as StandardMagenticManager,
103-
)
1043
from agent_framework_orchestrations import (
105-
__version__ as __version__,
4+
MAGENTIC_MANAGER_NAME,
5+
ORCH_MSG_KIND_INSTRUCTION,
6+
ORCH_MSG_KIND_NOTICE,
7+
ORCH_MSG_KIND_TASK_LEDGER,
8+
ORCH_MSG_KIND_USER_TASK,
9+
AgentBasedGroupChatOrchestrator,
10+
AgentOrchestrationOutput,
11+
AgentRequestInfoResponse,
12+
ConcurrentBuilder,
13+
GroupChatBuilder,
14+
GroupChatOrchestrator,
15+
GroupChatSelectionFunction,
16+
GroupChatState,
17+
HandoffAgentExecutor,
18+
HandoffAgentUserRequest,
19+
HandoffBuilder,
20+
HandoffConfiguration,
21+
HandoffSentEvent,
22+
MagenticAgentExecutor,
23+
MagenticBuilder,
24+
MagenticContext,
25+
MagenticManagerBase,
26+
MagenticOrchestrator,
27+
MagenticOrchestratorEvent,
28+
MagenticOrchestratorEventType,
29+
MagenticPlanReviewRequest,
30+
MagenticPlanReviewResponse,
31+
MagenticProgressLedger,
32+
MagenticProgressLedgerItem,
33+
MagenticResetSignal,
34+
SequentialBuilder,
35+
StandardMagenticManager,
36+
__version__,
10637
)
10738

10839
__all__ = [
@@ -113,6 +44,7 @@ __all__ = [
11344
"ORCH_MSG_KIND_USER_TASK",
11445
"AgentBasedGroupChatOrchestrator",
11546
"AgentOrchestrationOutput",
47+
"AgentRequestInfoResponse",
11648
"ConcurrentBuilder",
11749
"GroupChatBuilder",
11850
"GroupChatOrchestrator",

python/packages/orchestrations/agent_framework_orchestrations/__init__.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@
1717
except importlib.metadata.PackageNotFoundError:
1818
__version__ = "0.0.0" # Fallback for development mode
1919

20+
from ._base_group_chat_orchestrator import (
21+
BaseGroupChatOrchestrator,
22+
GroupChatRequestMessage,
23+
GroupChatRequestSentEvent,
24+
GroupChatResponseReceivedEvent,
25+
TerminationCondition,
26+
)
2027
from ._concurrent import ConcurrentBuilder
2128
from ._group_chat import (
2229
AgentBasedGroupChatOrchestrator,
@@ -53,6 +60,9 @@
5360
MagenticResetSignal,
5461
StandardMagenticManager,
5562
)
63+
from ._orchestration_request_info import AgentRequestInfoResponse
64+
from ._orchestration_state import OrchestrationState
65+
from ._orchestrator_helpers import clean_conversation_for_handoff, create_completion_message
5666
from ._sequential import SequentialBuilder
5767

5868
__all__ = [
@@ -63,9 +73,14 @@
6373
"ORCH_MSG_KIND_USER_TASK",
6474
"AgentBasedGroupChatOrchestrator",
6575
"AgentOrchestrationOutput",
76+
"AgentRequestInfoResponse",
77+
"BaseGroupChatOrchestrator",
6678
"ConcurrentBuilder",
6779
"GroupChatBuilder",
6880
"GroupChatOrchestrator",
81+
"GroupChatRequestMessage",
82+
"GroupChatRequestSentEvent",
83+
"GroupChatResponseReceivedEvent",
6984
"GroupChatSelectionFunction",
7085
"GroupChatState",
7186
"HandoffAgentExecutor",
@@ -85,7 +100,11 @@
85100
"MagenticProgressLedger",
86101
"MagenticProgressLedgerItem",
87102
"MagenticResetSignal",
103+
"OrchestrationState",
88104
"SequentialBuilder",
89105
"StandardMagenticManager",
106+
"TerminationCondition",
90107
"__version__",
108+
"clean_conversation_for_handoff",
109+
"create_completion_message",
91110
]

python/packages/core/agent_framework/_workflows/_base_group_chat_orchestrator.py renamed to python/packages/orchestrations/agent_framework_orchestrations/_base_group_chat_orchestrator.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@
1212
from dataclasses import dataclass
1313
from typing import Any, ClassVar, TypeAlias
1414

15+
from agent_framework._types import ChatMessage
16+
from agent_framework._workflows._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
17+
from agent_framework._workflows._events import WorkflowEvent
18+
from agent_framework._workflows._executor import Executor, handler
19+
from agent_framework._workflows._workflow_context import WorkflowContext
1520
from typing_extensions import Never
1621

17-
from .._types import ChatMessage
18-
from ._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
19-
from ._events import WorkflowEvent
20-
from ._executor import Executor, handler
2122
from ._orchestration_request_info import AgentApprovalExecutor
22-
from ._workflow_context import WorkflowContext
2323

2424
if sys.version_info >= (3, 12):
2525
from typing import override # type: ignore # pragma: no cover

python/packages/orchestrations/agent_framework_orchestrations/_concurrent.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
from agent_framework._workflows._checkpoint import CheckpointStorage
1313
from agent_framework._workflows._executor import Executor, handler
1414
from agent_framework._workflows._message_utils import normalize_messages_input
15-
from agent_framework._workflows._orchestration_request_info import AgentApprovalExecutor
1615
from agent_framework._workflows._workflow import Workflow
1716
from agent_framework._workflows._workflow_builder import WorkflowBuilder
1817
from agent_framework._workflows._workflow_context import WorkflowContext
1918
from typing_extensions import Never
2019

20+
from ._orchestration_request_info import AgentApprovalExecutor
21+
2122
logger = logging.getLogger(__name__)
2223

2324
"""Concurrent builder for agent-only fan-out/fan-in workflows.
@@ -481,7 +482,7 @@ def with_request_info(
481482
Returns:
482483
Self for fluent chaining
483484
"""
484-
from agent_framework._workflows._orchestration_request_info import resolve_request_info_filter
485+
from ._orchestration_request_info import resolve_request_info_filter
485486

486487
self._request_info_enabled = True
487488
self._request_info_filter = resolve_request_info_filter(list(agents) if agents else None)

python/packages/orchestrations/agent_framework_orchestrations/_group_chat.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,27 @@
3131
from agent_framework._types import ChatMessage
3232
from agent_framework._workflows._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
3333
from agent_framework._workflows._agent_utils import resolve_agent_id
34-
from agent_framework._workflows._base_group_chat_orchestrator import (
35-
BaseGroupChatOrchestrator,
36-
GroupChatParticipantMessage,
37-
GroupChatRequestMessage,
38-
GroupChatResponseMessage,
39-
GroupChatWorkflowContextOutT,
40-
ParticipantRegistry,
41-
TerminationCondition,
42-
)
4334
from agent_framework._workflows._checkpoint import CheckpointStorage
4435
from agent_framework._workflows._conversation_state import decode_chat_messages, encode_chat_messages
4536
from agent_framework._workflows._executor import Executor
46-
from agent_framework._workflows._orchestration_request_info import AgentApprovalExecutor
4737
from agent_framework._workflows._workflow import Workflow
4838
from agent_framework._workflows._workflow_builder import WorkflowBuilder
4939
from agent_framework._workflows._workflow_context import WorkflowContext
5040
from pydantic import BaseModel, Field
5141
from typing_extensions import Never
5242

43+
from ._base_group_chat_orchestrator import (
44+
BaseGroupChatOrchestrator,
45+
GroupChatParticipantMessage,
46+
GroupChatRequestMessage,
47+
GroupChatResponseMessage,
48+
GroupChatWorkflowContextOutT,
49+
ParticipantRegistry,
50+
TerminationCondition,
51+
)
52+
from ._orchestration_request_info import AgentApprovalExecutor
53+
from ._orchestrator_helpers import clean_conversation_for_handoff
54+
5355
if sys.version_info >= (3, 12):
5456
from typing import override # type: ignore # pragma: no cover
5557
else:
@@ -192,6 +194,8 @@ async def _handle_response(
192194
) -> None:
193195
"""Handle a participant response."""
194196
messages = self._process_participant_response(response)
197+
# Remove tool-related content to prevent API errors from empty messages
198+
messages = clean_conversation_for_handoff(messages)
195199
self._append_messages(messages)
196200

197201
if await self._check_terminate_and_yield(cast(WorkflowContext[Never, list[ChatMessage]], ctx)):
@@ -359,6 +363,8 @@ async def _handle_response(
359363
) -> None:
360364
"""Handle a participant response."""
361365
messages = self._process_participant_response(response)
366+
# Remove tool-related content to prevent API errors from empty messages
367+
messages = clean_conversation_for_handoff(messages)
362368
self._append_messages(messages)
363369
if await self._check_terminate_and_yield(cast(WorkflowContext[Never, list[ChatMessage]], ctx)):
364370
return
@@ -877,7 +883,7 @@ def with_request_info(self, *, agents: Sequence[str | AgentProtocol] | None = No
877883
Returns:
878884
Self for fluent chaining
879885
"""
880-
from agent_framework._workflows._orchestration_request_info import resolve_request_info_filter
886+
from ._orchestration_request_info import resolve_request_info_filter
881887

882888
self._request_info_enabled = True
883889
self._request_info_filter = resolve_request_info_filter(list(agents) if agents else None)

python/packages/orchestrations/agent_framework_orchestrations/_handoff.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,17 @@
4343
from agent_framework._types import AgentResponse, AgentResponseUpdate, ChatMessage
4444
from agent_framework._workflows._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
4545
from agent_framework._workflows._agent_utils import resolve_agent_id
46-
from agent_framework._workflows._base_group_chat_orchestrator import TerminationCondition
4746
from agent_framework._workflows._checkpoint import CheckpointStorage
4847
from agent_framework._workflows._events import WorkflowEvent
49-
from agent_framework._workflows._orchestrator_helpers import clean_conversation_for_handoff
5048
from agent_framework._workflows._request_info_mixin import response_handler
5149
from agent_framework._workflows._workflow import Workflow
5250
from agent_framework._workflows._workflow_builder import WorkflowBuilder
5351
from agent_framework._workflows._workflow_context import WorkflowContext
5452
from typing_extensions import Never
5553

54+
from ._base_group_chat_orchestrator import TerminationCondition
55+
from ._orchestrator_helpers import clean_conversation_for_handoff
56+
5657
if sys.version_info >= (3, 12):
5758
from typing import override # type: ignore # pragma: no cover
5859
else:

0 commit comments

Comments
 (0)