Skip to content
Tracon

TraconWorkflowContextExtensions

Namespace Tracon · Assembly Tracon.Workflows.dll

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

public static class TraconWorkflowContextExtensions
Inheritance
object ← TraconWorkflowContextExtensions
Inherited Members
object.GetType(), object.MemberwiseClone(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()

Returns the running workflow’s final parameter values.

public static IReadOnlyDictionary<string, string> GetRunParameters(this IWorkflowContext context)

context IWorkflowContext

The workflow context the function node received.

IReadOnlyDictionary<string, string>

The values the run was started with, with the workflow’s schema defaults applied. Read-only. Empty when the workflow declares no parameters.

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.

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}")]);
});

ArgumentNullException

context is null.

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.

ReportUsageAsync(IWorkflowContext, ToolCallUsage)

Section titled “ ReportUsageAsync(IWorkflowContext, ToolCallUsage)”

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

public static ValueTask<bool> ReportUsageAsync(this IWorkflowContext context, ToolCallUsage usage)

context IWorkflowContext

The workflow context the function node received.

usage 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).

ValueTask<bool>

A task that yields true when the item was recorded. false outside a Tracon workflow run, when the item is invalid (an empty 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.

It does not throw except for an empty argument. A false result does not interrupt the node: observability does not break functionality, the same rule as TraconToolUsage.Report.

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

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;
});

ArgumentNullException

context or usage is null.