microsoft / microsoft/agent-framework
Python: Support agent-to-agent communication across WorkflowExecutor boundaries
- Dominant language
- Python
- Stars
- 13.6k
- Forks
- 2.3k
- Avg merge
- 2d 45m
- Merged PRs (30d)
- 358
Description
### Description
MAF supports agent-to-agent communication when agents are composed directly, but the same communication pattern is not supported when the downstream agent is inside a nested workflow wrapped by `WorkflowExecutor`.
The generic composition looks like this:
```text
AgentExecutor
-> AgentExecutorResponse
-> WorkflowExecutor(nested_workflow)
-> downstream agent(s)
```
The upstream `AgentExecutor` emits `AgentExecutorResponse`. However, `WorkflowExecutor` exposes only the nested workflow's declared start input types. A nested workflow that accepts `str`, `Message`, `list[str | Message]`, or `AgentExecutorRequest` therefore rejects `AgentExecutorResponse`, resulting in `TypeCompatibilityError` during graph validation.
This creates an inconsistency in composition behavior:
- Direct agent-to-agent composition supports `AgentExecutorResponse` handoff and conversation chaining.
- Agent-to-nested-workflow composition does not support the same handoff, even when the nested workflow ultimately contains agents and expects conversational input.
- `WorkflowExecutor` is required when the nested workflow's state must be captured and restored in the parent checkpoint.
- Using `nested_workflow.as_agent()` provides the message conversion, but moves execution behind `WorkflowAgent` and does not embed the nested workflow's internal state in the parent checkpoint.
In our scenario, using `WorkflowExecutor` is not optional: the parent workflow must maintain the nested workflow checkpoint state so the complete parent and subworkflow execution can be resumed from the parent's checkpoint. Replacing the nested workflow with `as_agent()` avoids the type mismatch but does not satisfy this checkpointing requirement.
Users must currently write custom glue code to unwrap `AgentExecutorResponse` before passing it to `WorkflowExecutor`, which makes a common agent composition pattern unnecessarily difficult and prevents the parent-owned checkpointing model from being used without custom code.
### Proposed capability
Add an explicit, built-in agent-response input mode or adapter for `WorkflowExecutor`, for example:
```python
WorkflowExecutor(
nested_workflow,
id="nested_workflow",
input_mode="agent_response",
)
```
The behavior should define whether the nested workflow receives `AgentExecutorResponse.agent_response.messages` or the full conversation, and should continue to capture and restore the nested workflow state as part of the parent checkpoint.
An alternative API could expose a standard framework adapter that unwraps `AgentExecutorResponse` to `list[Message]` while remaining checkpoint-aware.
### Expected outcome
Agents should be able to communicate through nested workflow boundaries using the same explicit handoff semantics as direct agent-to-agent composition, without custom adapter code, while preserving a single parent checkpoint containing the complete parent and nested workflow state.
### Additional context
This is an API/composition gap rather than an unexpected type-validation failure: the current contracts are internally consistent, but agent-to-agent composition is not consistently available across hierarchical workflow boundaries. `allow_direct_output` and `propagate_request` do not address the input type conversion.
Contributor guide
Assessment
This issue has not been assessed yet.