# TraconWorkflowContextExtensions

> 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.traconworkflowcontextextensions/
> Summary: TraconWorkflowContextExtensions: What a function node reads from, and reports to, its workflow run: the run's parameter values and the non-token usage it spent.

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

What a function node reads from, and reports to, its workflow run: the run's parameter
values and the non-token usage it spent.

```csharp
public static class TraconWorkflowContextExtensions
```

<dl class="api-relations"><dt>Inheritance</dt><dd><a href="https://learn.microsoft.com/dotnet/api/system.object">object</a> ← <a href="/api/tracon.traconworkflowcontextextensions/">TraconWorkflowContextExtensions</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>

## Methods

### <a id="Tracon_TraconWorkflowContextExtensions_GetRunParameters_Microsoft_Agents_AI_Workflows_IWorkflowContext_"></a> GetRunParameters\(IWorkflowContext\)

Returns the running workflow's final parameter values.

```csharp
public static IReadOnlyDictionary<string, string> GetRunParameters(this IWorkflowContext context)
```

#### Parameters

`context` IWorkflowContext

The workflow context the function node received.

#### Returns

 [IReadOnlyDictionary](https://learn.microsoft.com/dotnet/api/system.collections.generic.ireadonlydictionary\-2)<[string](https://learn.microsoft.com/dotnet/api/system.string), [string](https://learn.microsoft.com/dotnet/api/system.string)\>

The values the run was started with, with the workflow's schema defaults
applied. Read-only. Empty when the workflow declares no parameters.

#### Remarks

The values come from the run, not from MAF's state: the workflow engine
has no way to seed a graph's initial state, so Tracon carries the values
in the run's own scope. A resumed run, or a run that continues after a
human answer, reads the same values as the run it continues.

```csharp
builder.AddTracon()
       .UseWorkflows()
       .AddWorkflowFunction<List<ChatMessage>, List<ChatMessage>>(
           "narrate",
           provider => (messages, context, cancellationToken) =>
           {
               var voice = context.GetRunParameters()["voice"];
               return ValueTask.FromResult<List<ChatMessage>>(
                   [new ChatMessage(ChatRole.User, $"{voice}: {messages[^1].Text}")]);
           });
```

#### Exceptions

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

 [InvalidOperationException](https://learn.microsoft.com/dotnet/api/system.invalidoperationexception)

Called outside a Tracon workflow run. An empty dictionary would hide the
wiring mistake: a test that forgets to open a run would read "no values"
and pass, and the same code in production would read the real ones.

### <a id="Tracon_TraconWorkflowContextExtensions_ReportUsageAsync_Microsoft_Agents_AI_Workflows_IWorkflowContext_Tracon_ToolCallUsage_"></a> ReportUsageAsync\(IWorkflowContext, ToolCallUsage\)

Reports what the function node spent that is not tokens: a text-to-speech
character, a render second, a GPU minute.

```csharp
public static ValueTask<bool> ReportUsageAsync(this IWorkflowContext context, ToolCallUsage usage)
```

#### Parameters

`context` IWorkflowContext

The workflow context the function node received.

`usage` [ToolCallUsage](/api/tracon.toolcallusage/)

The item: the unit and quantity, and the amount when the node knows it. Every call
adds one item; the node reports once per step, not per chunk (at most 1,000 items per run).

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[bool](https://learn.microsoft.com/dotnet/api/system.boolean)\>

A task that yields [true](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/bool) when the item was recorded.
[false](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/bool) outside a Tracon workflow run, when the item is invalid
(an empty [ToolCallUsage.Unit](/api/tracon.toolcallusage/#Tracon_ToolCallUsage_Unit), a negative quantity or amount, or a
value beyond what a column holds), and when the run already reported the most
items it can; the cause is logged.

#### Remarks

**It does not throw** except for an empty argument. A [false](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/bool)
result does not interrupt the node: observability does not break functionality, the
same rule as [TraconToolUsage.Report](/api/tracon.tracontoolusage/#Tracon_TraconToolUsage_Report_Tracon_ToolCallUsage_).

**What the item does.** It is written to the run's detail at once
(`GET /api/runs/{runId}/usage`) and is not cancelled with the run: the work was
done and billed. Its amount joins the run's non-token total, which the run's budget,
the tenant's quota and the `run.completed` webhook count beside the token cost.
Only an amount in `Tracon:Pricing:Currency` joins (an item that names no currency is
in it); an item with no amount, or in another currency, is listed and counted as not
added. Tracon never prices the item for you: the node knows its provider's price, and
[ToolCallUsage.Cost](/api/tracon.toolcallusage/#Tracon_ToolCallUsage_Cost) is the amount the node computed.

**Retries keep their items.** A node that fails and is retried keeps the
items of the failed attempt: the provider billed that attempt.

**An item reported after the run closed** (a node that outlived its
timeout, then finished) is kept in the run's detail and does not change the run's
total: the quota entry and the webhook were already written. A body that honours its
token does not reach this case.

The item names the node it was reported from. In a graph built in code, a custom
`Executor` that is not a function node registered with Tracon reports with no node name.

```csharp
builder.AddTracon()
       .UseWorkflows()
       .AddWorkflowFunction<List<ChatMessage>, string>(
           "narrate",
           provider => async (messages, context, cancellationToken) =>
           {
               var text = messages[messages.Count - 1].Text;

               // ... synthesize the speech with your provider, then report what it billed.
               await context.ReportUsageAsync(new ToolCallUsage
               {
                   Unit = ToolUsageUnits.Characters,
                   Quantity = text.Length,
                   Cost = text.Length * 0.00003m,
                   Currency = "USD",
                   Provider = "elevenlabs",
                   Model = "eleven_multilingual_v2",
               });

               return text;
           });
```

#### Exceptions

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