microsoft / microsoft/agent-framework
.NET: [Feature]: .NET - Allow enabling workflow-level OpenTelemetry when using HandoffWorkflowBuilder
@TaoChenOSU is already working on this.
Since Jun 4, 2026.
- Dominant language
- Python
- Stars
- 13.6k
- Forks
- 2.3k
- Avg merge
- 2d 45m
- Merged PRs (30d)
- 358
Description
### Description
When building a handoff workflow with `HandoffWorkflowBuilder`, there does not appear to be a public way to enable workflow-level OpenTelemetry instrumentation.
The lower-level `WorkflowBuilder` already supports workflow telemetry through `WithOpenTelemetry(...)`, which is useful for observing workflow execution spans such as:
* `workflow.build`
* `workflow.session` / `workflow_invoke`
* `edge_group.process`
* `executor.process`
* `message.send`
However, `HandoffWorkflowBuilder` encapsulates the internal `WorkflowBuilder` instance. In `Build()`, it creates an internal `WorkflowBuilder`, wires the handoff start/end executors and `HandoffAgentExecutor` instances, then directly builds the workflow. Because the internal builder is not exposed and no telemetry-specific method is available on `HandoffWorkflowBuilder`, users can enable telemetry at the agent and/or chat client layers, but cannot easily enable the workflow-level telemetry that explains the handoff routing itself.
This is especially important for handoff workflows because the interesting production debugging signals are often at the workflow/routing layer, not only at the LLM call layer:
* which agent owned the current turn
* whether a handoff actually occurred
* which agent handed off to which target agent
* whether the message was delivered, dropped, buffered, or failed during edge processing
* where a run stopped: workflow, executor, edge routing, message delivery, approval, checkpoint, or model/tool call
### Code Sample
```markdown
### Current behavior
This style is supported when using `WorkflowBuilder` directly:
Workflow workflow = new WorkflowBuilder(startExecutor)
.AddEdge(startExecutor, nextExecutor)
.WithOutputFrom(nextExecutor)
.WithOpenTelemetry(options =>
{
options.EnableSensitiveData = false;
}, activitySource)
.Build();
But this style does not appear to be available for handoff workflows:
Workflow workflow = AgentWorkflowBuilder
.CreateHandoffBuilderWith(triageAgent)
.WithHandoff(triageAgent, refundAgent, "Handle refund requests.")
.WithHandoff(refundAgent, triageAgent, "Return to triage when the refund flow is complete.")
// No apparent way to call WithOpenTelemetry(...) for the internal WorkflowBuilder.
.Build();
### Expected behavior
It should be possible to opt into workflow-level OpenTelemetry when using `HandoffWorkflowBuilder`, without exposing or mutating the internal workflow graph.
For example:
Workflow workflow = AgentWorkflowBuilder
.CreateHandoffBuilderWith(triageAgent)
.WithHandoff(triageAgent, refundAgent, "Handle refund requests.")
.WithHandoff(refundAgent, triageAgent, "Return to triage when the refund flow is complete.")
.WithOpenTelemetry(options =>
{
options.EnableSensitiveData = false;
}, activitySource)
.Build();
This would allow users to observe workflow-level spans for the handoff orchestration while keeping agent-level and chat-client-level telemetry separately configurable.
### Proposed API
Add a telemetry pass-through method to `HandoffWorkflowBuilderCore`:
public TBuilder WithOpenTelemetry(
Action? configure = null,
ActivitySource? activitySource = null)
{
// Store the configuration and apply it to the internal WorkflowBuilder before Build().
}
Then apply it inside `Build()` before the internal workflow is built:
public Workflow Build()
{
HandoffsStartExecutor start = new(this._returnToPrevious);
HandoffsEndExecutor end = new(this._returnToPrevious);
WorkflowBuilder builder = new(start);
if (this._workflowTelemetryEnabled)
{
builder.WithOpenTelemetry(this._configureWorkflowTelemetry, this._activitySource);
}
// Existing handoff graph construction remains unchanged.
return builder.WithOutputFrom(end).Build();
}
```
### Language/SDK
.NET
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.