Skip to content

Python: Add middleware sample to show filtering messages between agents (#3556) - #6143

Closed
pratik wayase (PratikWayase) wants to merge 2 commits into
microsoft:mainfrom
PratikWayase:feat/middleware-message-filter-sample-3556
Closed

Python: Add middleware sample to show filtering messages between agents (#3556)#6143
pratik wayase (PratikWayase) wants to merge 2 commits into
microsoft:mainfrom
PratikWayase:feat/middleware-message-filter-sample-3556

Conversation

@PratikWayase

Copy link
Copy Markdown
Contributor

Motivation and Context

This PR adds a sample demonstrating how middleware can be used to intercept and process messages between agents in a group chat workflow.

Currently, there is no built-in middleware hook in GroupChatBuilder for message interception. This sample provides a user-space pattern to achieve this behavior without modifying the core framework.

This addresses issue #3556 by illustrating how developers can implement:

  • Content filtering
  • Message transformation
  • Access control between agents

Description

This change updates the group_chat_agent_manager.py sample to include a middleware-style pattern for message interception.

Key aspects of the implementation:

  • Introduces a simple MessageInterceptor callable interface:

    • Input: Message
    • Output: Message or None (to drop messages)
  • Demonstrates multiple middleware use cases:

    • Content filtering (e.g., redact or drop sensitive messages)
    • Message transformation (e.g., tagging for audit/logging)
    • Access control (e.g., blocking specific agents)
  • Implements a wrapper (run_with_message_middleware) that:

    • Intercepts streaming responses (intermediate events)
    • Processes final outputs (output events)
    • Applies middleware without requiring changes to the core API
  • Documents patterns and trade-offs:

    • Middleware chaining
    • Message dropping vs redaction
    • Execution ordering considerations

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • This is not a breaking change
  • All unit tests pass, and I have added new tests where possible

Copilot AI review requested due to automatic review settings May 28, 2026 10:40
@moonbox3 Evan Mattson (moonbox3) added the python Usage: [Issues, PRs], Target: Python label May 28, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a message-middleware demonstration layer to the group chat agent manager sample. A composable interceptor pattern is introduced (content filtering, tagging, sender block-listing) and applied via a user-space wrapper around workflow.run until native builder support exists.

Changes:

  • Introduces MessageInterceptor type and compose_middleware plus three example interceptors.
  • Wraps workflow execution with run_with_message_middleware to mutate intermediate/output events.
  • Updates docstring, task prompt, and removes the duplicate termination_condition constructor argument in favor of .with_termination_condition(...).

Comment on lines +46 to +51
try:
return msg.replace(text=safe_text) if hasattr(msg, "replace") else Message(
role=msg.role, author_name=msg.author_name, text=safe_text
)
except Exception:
return None
Comment on lines +96 to +99
async for event in workflow.run(task, stream=stream):
if event.type == "intermediate" and isinstance(event.data, AgentResponseUpdate):
original_text = event.data.text
if original_text:
intercepted = middleware(temp_msg)
if intercepted is None:
continue
event.data.text = intercepted.text
processed = middleware(msg)
if processed is not None:
filtered_messages.append(processed)
event.data = filtered_messages
middleware_pipeline = compose_middleware(
create_content_filter(forbidden_terms=["confidential", "internal-ip", "password"]),
create_message_tagger(prefix="AUDIT"),
create_sender_blocklist(blocked_agents=set())
Comment on lines +132 to +136
2. Transformation: Audit tagging, format enforcement, prompt sanitization
3. Access Control: Multi-tenant routing, cost gates, agent permissioning
4. Ordering Rule: Access Control → Content Filter → Transformation → Logging
5. Failure Mode: Dropping messages (`None`) removes context → prefer redaction tokens
6. Integration Note: This sample uses a wrapper pattern. Native hooks (e.g.,
Comment on lines +233 to +234
asyncio.run(main())

No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I do not think this closes #3556 as written. The issue asks for message interception between agents, but this sample wraps workflow.run() and post-processes emitted events after the group chat internals have already consumed the participant response. That means a dropped/redacted message can still be appended to the orchestrator conversation and broadcast to other participants before the wrapper sees it.

There are also current API mismatches: agent_framework.Event is not exported, Message uses contents=[...] rather than text=..., Message has no replace() method, WorkflowEvent is not a dataclass so dataclasses.replace(event, ...) will not work, and streamed updates are emitted as output events rather than intermediate events.

I think the best way to make this sample match #3556 is to show a custom BaseGroupChatOrchestrator that applies the interceptor before participant messages are appended to group-chat state or broadcast to other participants.

An executor/participant wrapper can transform an AgentExecutorResponse, but that feels less aligned with the issue: the request is specifically about message interception between agents in group chat. The orchestrator is already the central routing point for participant responses, speaker selection, and broadcasts, so it is the clearest place to demonstrate content filtering, message transformation, and access control without implying that caller-facing workflow.run() events are the actual inter-agent message channel.

p.s. I'd also prefer a better name for the sample too, please. And it needs to be added to the workflows samples README. Thanks.

@eavanvalkenburg

Copy link
Copy Markdown
Member

Considering the concerns raised by Evan Mattson (@moonbox3) and the lack of activity, I'm closing this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants