Skip to content
Tracon

WorkflowDefinition

Namespace Tracon · Assembly Tracon.Abstractions.dll

Represents the full definition of a workflow, whether defined through the UI or in code.

public sealed record WorkflowDefinition : IEquatable<WorkflowDefinition>
Inheritance
object ← WorkflowDefinition
Implements
IEquatable<WorkflowDefinition>
Inherited Members
object.GetType(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()

A definition is a graph, not code: it only wires together agents from the catalog. Users do not write new behavior, they arrange existing behavior. A free-form graph (custom Executor types) can only be defined in code, via AddWorkflow(name, factory).

WorkflowDefinition.AgentNames is a list of names only. Each name must resolve to an agent in the catalog; if it does not, compilation fails. The same rule applies to AgentDefinition.ToolNames and draws the same security boundary.

public WorkflowDefinition()

Gets the agent names to enter the graph. Order is meaningful for WorkflowKind.Sequential; for other kinds it defines the participant set.

public IReadOnlyList<string> AgentNames { get; init; }

IReadOnlyList<string>

Gets the short description of what the workflow does.

public string? Description { get; init; }

string?

Gets the display name shown in the UI. Name is used if left empty.

public string? DisplayName { get; init; }

string?

Gets the extra instruction that tells the model how to decide on a handoff. Used only for WorkflowKind.Handoff.

public string? HandoffInstructions { get; init; }

string?

Gets the built-in pattern to use.

public required WorkflowKind Kind { get; init; }

WorkflowKind

Gets the manager agent’s name. Required for WorkflowKind.Magentic, unused in other patterns.

public string? ManagerAgentName { get; init; }

string?

Gets the maximum number of turns. The only guard against an infinite loop in the WorkflowKind.GroupChat, WorkflowKind.Handoff, and WorkflowKind.Magentic patterns.

public int? MaxIterations { get; init; }

int?

Gets the workflow’s unique name. Serves as the key in the catalog and in API routes.

public required string Name { get; init; }

string

Gets the ordered node list for a WorkflowKind.Sequential workflow that mixes agent and function nodes.

public IReadOnlyList<WorkflowNodeReference> Nodes { get; init; }

IReadOnlyList<WorkflowNodeReference>

Empty for every definition that does not use a function node - which keeps WorkflowDefinition.AgentNames driving the graph exactly as before this field existed. When non-empty, WorkflowDefinition.Kind must be WorkflowKind.Sequential and WorkflowDefinition.AgentNames must be empty; the validator in Tracon.Core enforces both rules. Microsoft Agent Framework’s ready-made builders for the other four patterns (Concurrent, Handoff, GroupChat, Magentic) accept only agents, so a function node cannot enter those graphs without hand-writing their orchestration logic - out of scope.

Whether each function name is actually registered is checked at save time (the HTTP layer, against the function registry) and again at compile time, unlike agent names - which are checked only at compile time because the agent catalog can change between the two. The function registry cannot: it is fixed for the lifetime of the process, so checking early gives an honest guarantee.

A function node may carry WorkflowNodeReference.Settings, checked the same way against the settings type its function declares (the save-time settings check) and read again at compile time, because that type can change between deployments.

A chain of agents only may be stored either way: as WorkflowDefinition.AgentNames or as WorkflowDefinition.Nodes, and the server accepts both. The console writes WorkflowDefinition.Nodes only when the chain holds at least one function node.

Gets the run parameters the workflow accepts. Empty for a workflow that takes none.

public IReadOnlyList<AgentParameter> Parameters { get; init; }

IReadOnlyList<AgentParameter>

A run supplies values for these names (WorkflowRunRequest.Parameters). The set is the workflow’s contract: each agent step receives the values whose names its own schema declares, and binds them into its instructions the way a direct run of that agent would. A name the workflow declares but a step does not is dropped for that step.

Only the structure is checked when the definition is saved (valid, unique names). Whether every participant’s required parameters are covered is checked when a run starts: the participants live in the agent catalog, which can change after the workflow is saved.

A workflow defined in code (AddWorkflow) carries no definition and therefore declares no parameters; a value supplied to it is rejected. AgentParameter.Kind labels the value for the console only; every value travels as a string.

Gets how long a human request of this workflow may wait for an answer before the run that waits on it is closed. null (the default) means it waits without limit.

public TimeSpan? RequestTimeout { get; init; }

TimeSpan?

A run that waits for a human keeps its request event, its checkpoints and its input row without limit, because answering needs them (a retention policy does not delete them while the run waits). A limit is what lets those rows go: when the time passes the run is closed RunStatus.Failed with the error type WorkflowRequestExpired, or RunStatus.Completed without an error when every request it waited on was answered, and the retention policy deletes its rows on its next round. An answer to a run that was closed is refused with 400.

The time counts from the moment the run published the request. A run that waits keeps the limit of the definition version it recorded, so an edit made while it waits changes neither the graph nor the limit. Must be from one minute to 365 days.

Gets whether the plan the manager agent builds must be approved by a human before execution starts. Applies only to WorkflowKind.Magentic.

public bool RequirePlanApproval { get; init; }

bool

When enabled, Microsoft Agent Framework publishes an external request at the end of the first super-step; the run becomes RunStatus.AwaitingInput and its state is written to a checkpoint. The response is given via POST /api/workflows/runs/{runId}/respond: the plan is either approved or sent back with revision text.

Cost. The manager agent runs again on every turn; a revision request makes it rebuild the plan from scratch. The default of false is deliberate: a run never stalls half-way unless a definition opts in explicitly (the no-surprises rule).

Gets how the workflow treats more than one answer to the same pending human request. WorkflowResponseMode.Branch (the default) opens a new run for every answer; WorkflowResponseMode.SingleAnswer allows one answer per request.

public WorkflowResponseMode ResponseMode { get; init; }

WorkflowResponseMode

Applies to every kind. A stored definition’s requests come from a manager agent’s plan approval (WorkflowDefinition.RequirePlanApproval); a workflow defined in code chooses its mode when it is registered.

A waiting run is answered under the mode of the definition version it recorded. Changing the mode affects runs started after the change.

Gets the longest time one run of this workflow may take. null (the default) uses the installation’s Tracon:Workflows:RunTimeout.

public TimeSpan? RunTimeout { get; init; }

TimeSpan?

The value replaces the installation’s run timeout for this workflow only, and it behaves the same way: the deadline starts when the run starts (a wait for a MaxConcurrentRuns slot counts too), it cancels the token every node is given, and a run that reaches it ends RunStatus.Canceled with an error that names this field.

It may only shorten the installation’s value unless the host allows more. A running workflow holds one of the slots that every tenant shares, so the host decides how long one may hold it: Tracon:Workflows:MaxRunTimeout is the ceiling. While it is not set, a value above Tracon:Workflows:RunTimeout is refused when the definition is saved (400). A stored value above a ceiling that was lowered later still runs, cut to the ceiling.

Must be from one millisecond to about 49.7 days. A node’s own timeout (WorkflowNodeReference.Timeout) is not checked against this value: the two answer different questions, and whichever ends first stops the node.

A WorkflowKind.Sequential chain bounds each step with WorkflowNodeReference.Timeout; the other patterns (WorkflowDefinition.AgentNames) have no nodes, so this value and the installation’s Tracon:AgentGraph:ChildDeadline bound them.

Gets the tenant the definition belongs to. null for workflows defined in code.

public string? TenantId { get; init; }

string?

Gets the last modification time (UTC).

public DateTimeOffset? UpdatedAt { get; init; }

DateTimeOffset?

Gets the definition version. Increments by one on every save and is never reused: the store keeps every version (see IWorkflowDefinitionStore).

public int Version { get; init; }

int

public override bool Equals(object? obj)

obj object?

bool

public bool Equals(WorkflowDefinition? other)

other WorkflowDefinition?

bool

public override int GetHashCode()

int

public override string ToString()

string

operator ==(WorkflowDefinition?, WorkflowDefinition?)

Section titled “ operator ==(WorkflowDefinition?, WorkflowDefinition?)”
public static bool operator ==(WorkflowDefinition? left, WorkflowDefinition? right)

left WorkflowDefinition?

right WorkflowDefinition?

bool

operator !=(WorkflowDefinition?, WorkflowDefinition?)

Section titled “ operator !=(WorkflowDefinition?, WorkflowDefinition?)”
public static bool operator !=(WorkflowDefinition? left, WorkflowDefinition? right)

left WorkflowDefinition?

right WorkflowDefinition?

bool