# WorkflowAgentBinding

> Tracon documentation. Tracon is a .NET package family that adds a control
> plane on Microsoft Agent Framework, published as NuGet packages that run
> inside your own ASP.NET Core application.
>
> Page: https://tracon.dev/api/tracon.workflowagentbinding/
> Summary: WorkflowAgentBinding: Binds catalog agents to a workflow graph defined in code.

<div class="api-provenance">Namespace Tracon · Assembly <code>Tracon.Workflows.dll</code></div>

Binds catalog agents to a workflow graph defined in code.

```csharp
public static class WorkflowAgentBinding
```

<dl class="api-relations"><dt>Inheritance</dt><dd><a href="https://learn.microsoft.com/dotnet/api/system.object">object</a> ← <a href="/api/tracon.workflowagentbinding/">WorkflowAgentBinding</a></dd><dt>Inherited Members</dt><dd><a href="https://learn.microsoft.com/dotnet/api/system.object.gettype">object.GetType()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone">object.MemberwiseClone()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.tostring">object.ToString()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)">object.Equals(object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)">object.Equals(object?, object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.referenceequals">object.ReferenceEquals(object?, object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.gethashcode">object.GetHashCode()</a></dd></dl>

## Remarks

**Do not put an agent taken from the catalog DIRECTLY into the
graph.** `IAgentCatalog.ResolveAsync` returns an agent carrying
the run-recording wrapper, but Microsoft Agent Framework calls it with
`options = null`; the wrapper cannot read tree info from the incoming
settings and opens its own root row instead. Result: the workflow run
looks empty, the agents are independent roots in the list, and the
waterfall is drawn wrong. Measured: in the sample app, the tree
came back as one row instead of three.

This helper wraps the agent with [ChildAgentInvoker](/api/tracon.childagentinvoker/). The
wrapper reads tree info from the ambient scope, applies the depth/budget/
tenant limits, and attaches the sub-run under the workflow row. For
workflows defined from the UI, the compiler does the same wrapping.

```csharp
tracon.AddWorkflow("summarize-and-translate", services =>
    AgentWorkflowBuilder.BuildSequential("summarize-and-translate",
    [
        services.GetWorkflowAgent("summarize-and-translate", "summarizer"),
        services.GetWorkflowAgent("summarize-and-translate", "translator"),
    ]));
```

To run an agent as a plain step of a graph with a revision loop or a human approval - a step that takes the
messages of the node before it and passes on its answer - use
[WorkflowAgentBinding.GetWorkflowAgentStep](/api/tracon.workflowagentbinding/) instead.

## Methods

### <a id="Tracon_WorkflowAgentBinding_GetWorkflowAgent_System_IServiceProvider_System_String_System_String_System_String_"></a> GetWorkflowAgent\(IServiceProvider, string, string, string?\)

Wraps a catalog agent in a form that can be placed in a workflow graph.

```csharp
public static AIAgent GetWorkflowAgent(this IServiceProvider services, string workflowName, string agentName, string? description = null)
```

#### Parameters

`services` [IServiceProvider](https://learn.microsoft.com/dotnet/api/system.iserviceprovider)

The service provider.

`workflowName` [string](https://learn.microsoft.com/dotnet/api/system.string)

The name of the enclosing workflow. Appears in error messages.

`agentName` [string](https://learn.microsoft.com/dotnet/api/system.string)

The name of the agent to bind.

`description` [string](https://learn.microsoft.com/dotnet/api/system.string)?

A description of what the agent does. In the `GroupChat` and
`Magentic` patterns it reaches the participant list sent to the
model; leaving it empty makes it harder for the manager agent to know
when to call whom.

#### Returns

 AIAgent

An agent that can be placed in the graph.

#### Remarks

The agent is resolved **lazily**: this call does not read
the catalog, it only builds a wrapper. This way, when an agent
definition changes, the compiled workflow does not go stale, and the
factory being synchronous causes no problem.

**The agent is meant to be hosted** by a ready-made pattern or an `AIAgentBinding`: when
its tool needs approval, the wrapper passes the request on and the host turns it into a workflow request
that waits for a person. Calling the returned agent yourself from a plain function node would drop the
request, so a step of that kind binds the agent with [WorkflowAgentBinding.GetWorkflowAgentStep](/api/tracon.workflowagentbinding/)
instead, which refuses the approval.

The **same instance** is returned for the same
`(workflowName, agentName)` pair. This is deliberate: Microsoft
Agent Framework derives executor ids from the agent instance's
identity, and returning a new instance on every call would make
checkpoints incompatible.

#### Exceptions

 [ArgumentNullException](https://learn.microsoft.com/dotnet/api/system.argumentnullexception)

`services` is [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null).

 [ArgumentException](https://learn.microsoft.com/dotnet/api/system.argumentexception)

One of the names is empty.

### <a id="Tracon_WorkflowAgentBinding_GetWorkflowAgentStep_System_IServiceProvider_System_String_System_String_"></a> GetWorkflowAgentStep\(IServiceProvider, string, string\)

Binds a catalog agent as a plain step of a workflow graph defined in code - a node that takes
the messages of the node before it and passes on the agent's answer.

```csharp
public static ExecutorBinding GetWorkflowAgentStep(this IServiceProvider services, string workflowName, string agentName)
```

#### Parameters

`services` [IServiceProvider](https://learn.microsoft.com/dotnet/api/system.iserviceprovider)

The service provider.

`workflowName` [string](https://learn.microsoft.com/dotnet/api/system.string)

The name of the enclosing workflow. Appears in error messages.

`agentName` [string](https://learn.microsoft.com/dotnet/api/system.string)

The name of the agent to run. Also the id of the step.

#### Returns

 ExecutorBinding

The executor binding to put in the graph.

#### Remarks

Everything the other overload says applies here too; the step runs with no timeout of its own and the
agent's current version.

#### Exceptions

 [ArgumentNullException](https://learn.microsoft.com/dotnet/api/system.argumentnullexception)

`services` is [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null).

 [ArgumentException](https://learn.microsoft.com/dotnet/api/system.argumentexception)

One of the names is empty.

### <a id="Tracon_WorkflowAgentBinding_GetWorkflowAgentStep_System_IServiceProvider_System_String_System_String_System_Action_Tracon_WorkflowAgentStepOptions__"></a> GetWorkflowAgentStep\(IServiceProvider, string, string, Action<WorkflowAgentStepOptions\>\)

Binds a catalog agent as a plain step of a workflow graph defined in code, with the step's own
timeout and a version pin, fixed or read from a run parameter.

```csharp
public static ExecutorBinding GetWorkflowAgentStep(this IServiceProvider services, string workflowName, string agentName, Action<WorkflowAgentStepOptions> configure)
```

#### Parameters

`services` [IServiceProvider](https://learn.microsoft.com/dotnet/api/system.iserviceprovider)

The service provider.

`workflowName` [string](https://learn.microsoft.com/dotnet/api/system.string)

The name of the enclosing workflow. Appears in error messages.

`agentName` [string](https://learn.microsoft.com/dotnet/api/system.string)

The name of the agent to run. Also the id of the step.

`configure` [Action](https://learn.microsoft.com/dotnet/api/system.action\-1)<[WorkflowAgentStepOptions](/api/tracon.workflowagentstepoptions/)\>

Sets the step's timeout and version pin or version parameter; called once, here.

#### Returns

 ExecutorBinding

The executor binding to put in the graph.

#### Remarks

**This is not [WorkflowAgentBinding.GetWorkflowAgent](/api/tracon.workflowagentbinding/#Tracon_WorkflowAgentBinding_GetWorkflowAgent_System_IServiceProvider_System_String_System_String_System_String_).** That helper returns an agent that a
ready-made pattern or an `AIAgentBinding` hosts; the host runs it only when it is sent a
`Workflows.TurnToken`, and nothing sends one to a node that is not the graph's entry. A step bound
here is a plain function executor: it runs when a message arrives, wherever the edge comes from - a
back edge included - so a revision loop works. The price is that it streams no token deltas into the
workflow's event feed and keeps no Microsoft Agent Framework session; a step that revises a draft
carries the draft and the feedback in the messages it is given.

**The id of the step is the agent's name**, as in a stored chain, so an agent is used
once in a graph. The agent runs as a child of the workflow's run: it records its own run row with the
full message and usage history, and the tree's depth, budget and tenant rules apply. The step does not
stream: it asks the agent for its whole answer, so the structured-response repair
(`Tracon:StructuredResponse`) and a loop agent's final iteration work as they do for a plain
agent run.

**A version is fixed in the graph or chosen by the run, never both.**
[WorkflowAgentStepOptions.AgentVersion](/api/tracon.workflowagentstepoptions/#Tracon_WorkflowAgentStepOptions_AgentVersion) fixes it for every run;
[WorkflowAgentStepOptions.AgentVersionParameter](/api/tracon.workflowagentstepoptions/#Tracon_WorkflowAgentStepOptions_AgentVersionParameter) names a run parameter that carries it. The
factory of a graph built in code cannot read the run's parameters, so the step reads the value each
time it runs.

The step takes and passes on a `List<ChatMessage>`; put a node between it and a node of
another type.

```csharp
tracon.AddWorkflow("review-and-revise", services =>
{
    var writer = services.GetWorkflowAgentStep("review-and-revise", "writer", step =>
    {
        step.Timeout = TimeSpan.FromMinutes(3);
        step.AgentVersion = 4;
    });
    var check = services.GetWorkflowFunction("check");

    return new WorkflowBuilder(writer)
        .AddEdge(writer, check)
        .WithOutputFrom(check)
        .WithName("review-and-revise")
        .Build();
});
```

#### Exceptions

 [ArgumentNullException](https://learn.microsoft.com/dotnet/api/system.argumentnullexception)

One of the parameters is [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null).

 [ArgumentException](https://learn.microsoft.com/dotnet/api/system.argumentexception)

One of the names is empty, [WorkflowAgentStepOptions.AgentVersionParameter](/api/tracon.workflowagentstepoptions/#Tracon_WorkflowAgentStepOptions_AgentVersionParameter) is empty, or
both it and [WorkflowAgentStepOptions.AgentVersion](/api/tracon.workflowagentstepoptions/#Tracon_WorkflowAgentStepOptions_AgentVersion) are set.

 [ArgumentOutOfRangeException](https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception)

[WorkflowAgentStepOptions.Timeout](/api/tracon.workflowagentstepoptions/#Tracon_WorkflowAgentStepOptions_Timeout) is outside the range an agent step accepts, or
[WorkflowAgentStepOptions.AgentVersion](/api/tracon.workflowagentstepoptions/#Tracon_WorkflowAgentStepOptions_AgentVersion) is less than 1.
