microsoft / microsoft/agent-framework
Python: Design question: why do Declarative InvokeAzureAgent and WorkflowBuilder AgentExecutor differ in agent conversation semantics?
- Dominant language
- Python
- Stars
- 13.6k
- Forks
- 2.3k
- Avg merge
- 2d 45m
- Merged PRs (30d)
- 358
Description
## Summary
In Microsoft Agent Framework (Python), invoking an agent via **declarative YAML** (`InvokeAzureAgent`) and via a **hand-authored** `WorkflowBuilder` / orchestration path (`AgentExecutor`) appear to use **different conversation / history models**, even though both ultimately run an `Agent`.
From a product/design perspective, declarative vs code-first often looks like *two expression forms of the same workflow model*. If that is the intent, the **agent conversation semantics would ideally be aligned**. Today they do not seem to be. We would like to understand the **intentional design rationale** (and whether convergence is planned).
## Observed behavior (Python)
### Declarative: `InvokeAzureAgent` → `InvokeAzureAgentExecutor`
- Resolves history from declarative workflow state:
- default: `Conversation.messages`
- with `conversationId`: `System.conversations..messages`
- Calls `agent.run(messages_for_agent, ...)` **without** passing `session=`
- Appends results back into that state path
- `CreateConversation` allocates a new id + empty bucket under `System.conversations`
- Continuity is therefore **workflow-state / checkpoint scoped**, not `AgentSession` + `HistoryProvider`
### Programmatic: `WorkflowBuilder` / builders → `AgentExecutor`
- Holds `self._session` (`AgentSession`, created if none provided)
- Calls `agent.run(..., session=self._session)`
- Checkpoints `agent_session`
- With `HistoryProvider` (and related flags), history is persisted via the **session / provider** path
So the same conceptual step (“run this agent in a workflow”) has:
| Aspect | Declarative `InvokeAzureAgent` | `AgentExecutor` |
| --- | --- | --- |
| Primary history store | Declarative `Conversation*` state | `AgentSession` (+ optional `HistoryProvider`) |
| `session=` on `agent.run` | Not passed | Passed |
| Isolation knob | `conversationId` / `CreateConversation` | Separate sessions / providers |
| Role of agent | Action that mutates workflow conversation state | First-class graph participant with its own session |
## Why this matters
Integrators building a single product surface (e.g. a canvas that compiles to declarative YAML *and* orchestration / code-built graphs) currently must document **two different agent meanings**:
- Canvas declarative “Agent” node ≈ `InvokeAzureAgent` semantics
- Orchestration / `add_agent` ≈ `AgentExecutor` semantics
That is surprising if declarative is meant to be a YAML encoding of the same workflow ideas as `WorkflowBuilder`.
## Questions for maintainers
1. **Was this divergence intentional?** If so, what were the design drivers (e.g. parity with .NET / Foundry declarative / Copilot Studio conversation model vs graph executors)?
2. Should consumers treat declarative and `WorkflowBuilder` as **two different agent models** (by design), rather than two syntaxes for one model?
3. Is there a **roadmap** to converge (e.g. declarative `InvokeAzureAgent` optionally using `AgentSession` / `HistoryProvider`, or documenting a single recommended continuity model)?
4. For isolation (sub-agent private context): is `CreateConversation` + `conversationId` the declarative equivalent of “a separate `AgentSession`”, or should those concepts remain intentionally distinct?
## References (current tree)
- `python/packages/declarative/.../_executors_agents.py` — `InvokeAzureAgentExecutor` (`messages_path`, `agent.run` without session)
- `python/packages/declarative/.../_executors_basic.py` — `CreateConversationExecutor`
- `python/packages/core/.../_workflows/_agent_executor.py` — `AgentExecutor` (`self._session`, `agent.run(..., session=...)`)
- Docs: [Declarative workflows](https://learn.microsoft.com/en-us/agent-framework/workflows/declarative) (`conversationId`, `CreateConversation`, etc.)
Happy to adjust assumptions if we misread the intended layering. Thanks!
Contributor guide
Research direction
Read python/packages/declarative/.../_executors_agents.py and _executors_basic.py alongside python/packages/core/.../_workflows/_agent_executor.py, then compare the referenced declarative workflow documentation. Trace how each executor stores history and passes sessions. Done requires a maintainer decision on whether the models should converge, remain distinct, or need clarified documentation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- ai, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100