microsoft / microsoft/agent-framework

.NET: [Feature]: .NET - Allow enabling workflow-level OpenTelemetry when using HandoffWorkflowBuilder

Open
#6,320 1 comment 3 reactions 1 assignee View on GitHub

@TaoChenOSU is already working on this.

Since Jun 4, 2026.

.NET
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.