.NET API
AgentRunBudget
Tracon.Abstractions.dllA run budget shared across an entire call tree.
public sealed class AgentRunBudget- Inheritance
- object ← AgentRunBudget
- Inherited Members
- object.GetType(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()
Remarks
Section titled “Remarks”This type is deliberately a class, not a record.
The budget is shared mutable state: every run in the tree uses the
same instance. A record invites copying; a copied budget
would give each branch its own limit, and the limit would lose its meaning.
Counters increment lock-free (Threading.Interlocked). Child runs start
concurrently: Microsoft Agent Framework’s background agents run without
blocking, so the same budget is read and written from multiple threads.
AgentRunBudget.TryReserveRun (the count and depth dimensions) only blocks a new child run from starting; it never interrupts a child run already in progress — cutting one off midway would leave the model with an incomplete context and would also corrupt the root run.
The token, cost, and duration dimensions are enforced the same way, by a
decorator installed inside the tool-call loop (RunBudgetChatClient,
internal to Tracon.Core): once AgentRunBudget.IsExhausted is
true, that decorator refuses the tree’s next
model call, so a long-running tool loop is cut off mid-run rather than
only at its next child call. The cutoff always lands between two model
turns, never inside one — the decorator only ever refuses a call it has
not yet made. A tool that itself runs long is not interrupted;
the cutoff waits for that tool call to finish and only then refuses the
model call that would follow it.
A workflow function node is gated at its start, on two of the
three: once AgentRunBudget.IsCostBudgetExhausted or AgentRunBudget.IsDurationBudgetExhausted
is true the node does not begin and the run ends
Failed with TraconRunBudgetExceededException. The token
dimension does not stop a node: it is on by default and a function node spends
no tokens. A node that is already running is never stopped, so the tree can
pass a ceiling by as much as its last node spends; the ceiling is not absolute.
A tool call is gated at its start on all three: once AgentRunBudget.IsExhausted is true it does not begin. The model’s next call is refused for the same condition, so no model reads the result of a tool call that starts now. The result of a refused call is a sentence that says the call did not start; a streaming run records the call as failed, and the run ends at its next model call as it always did. A tool that has started is never stopped, and tool calls that start together (concurrent tool calls) all start before any of them reports.
The budget of a workflow run that continues earlier runs starts from what they spent (AgentRunBudget.ConsumedTokens, AgentRunBudget.ConsumedCost, AgentRunBudget.StartedRuns) and has a AgentRunBudget.Deadline that is as far behind a fresh one as the earlier runs were executing: the ceiling is the logical run’s, and the time a workflow waited for a person is not counted.
Constructors
Section titled “Constructors”AgentRunBudget(TimeSpan?, TimeProvider?)
Section titled “ AgentRunBudget(TimeSpan?, TimeProvider?)”Creates a new run budget.
public AgentRunBudget(TimeSpan? maxDuration = null, TimeProvider? timeProvider = null)Parameters
Section titled “Parameters”maxDuration TimeSpan?
The wall-clock time the whole tree may take, taken at face value: unlike
the four init dimensions below, null
is the only value that means “no limit” — TimeSpan.Zero or
a negative value produces a AgentRunBudget.Deadline that has already
passed, the same way a raw MaxTotalTokens = 0 reads as
“exhausted from the start” rather than “unlimited”. The “zero/negative
means unlimited” convention is applied one layer up, in
TraconAgentGraphOptions.CreateBudget (Tracon.Core).
timeProvider TimeProvider?
The time source AgentRunBudget.Deadline is computed from and every later expiry check reads. Defaults to TimeProvider.System.
Properties
Section titled “Properties”ConsumedCost
Section titled “ ConsumedCost”The amount spent across the tree so far.
public decimal ConsumedCost { get; }Property Value
Section titled “Property Value”ConsumedTokens
Section titled “ ConsumedTokens”The tokens spent across the tree so far.
public long ConsumedTokens { get; }Property Value
Section titled “Property Value”Deadline
Section titled “ Deadline”The instant the tree’s time budget runs out. Computed once, when this budget was constructed; every run in the tree shares the same value. null when AgentRunBudget.MaxDuration is null. For a run that continues an earlier one it is earlier than a fresh budget’s by the time the earlier runs were executing.
public DateTimeOffset? Deadline { get; }Property Value
Section titled “Property Value”IsCostBudgetExhausted
Section titled “ IsCostBudgetExhausted”Whether the cost limit has been exceeded.
public bool IsCostBudgetExhausted { get; }Property Value
Section titled “Property Value”IsDurationBudgetExhausted
Section titled “ IsDurationBudgetExhausted”Whether the tree’s AgentRunBudget.Deadline has passed.
public bool IsDurationBudgetExhausted { get; }Property Value
Section titled “Property Value”IsExhausted
Section titled “ IsExhausted”Whether the tree has spent past its token, cost, or time limit. Does not reflect AgentRunBudget.MaxTotalRuns: the run-count limit only blocks starting a new child run (AgentRunBudget.TryReserveRun), it says nothing about whether the current run may keep calling its model.
public bool IsExhausted { get; }Property Value
Section titled “Property Value”IsTokenBudgetExhausted
Section titled “ IsTokenBudgetExhausted”Whether the token limit has been exceeded.
public bool IsTokenBudgetExhausted { get; }Property Value
Section titled “Property Value”MaxDepth
Section titled “ MaxDepth”The maximum allowed call depth. The root run is 0, so the default value allows a three-layer tree.
public int MaxDepth { get; init; }Property Value
Section titled “Property Value”MaxDuration
Section titled “ MaxDuration”The wall-clock time the whole tree may take, counted from when this budget was constructed. If null, there is no time limit.
public TimeSpan? MaxDuration { get; }Property Value
Section titled “Property Value”Remarks
Section titled “Remarks”A workflow run that continues an earlier one (a person’s answer, an operator’s resume, a recovery after an interruption) counts the time the earlier runs were executing too, and not the time the workflow waited for a person: the limit is the logical run’s.
MaxTotalCost
Section titled “ MaxTotalCost”The maximum amount spendable across the tree. If null, there is no cost limit.
public decimal? MaxTotalCost { get; init; }Property Value
Section titled “Property Value”Remarks
Section titled “Remarks”Cannot be enforced when a model call’s pricing is undefined (PricingSource.Unknown); the token limit applies instead, the same fallback QuotaDefinition.MaxCost uses.
MaxTotalRuns
Section titled “ MaxTotalRuns”The maximum number of child runs that may start. The root run is not counted toward this number. If null, there is no count limit.
public int? MaxTotalRuns { get; init; }Property Value
Section titled “Property Value”int?
MaxTotalTokens
Section titled “ MaxTotalTokens”The maximum tokens spendable across the tree. If null, there is no token limit.
public long? MaxTotalTokens { get; init; }Property Value
Section titled “Property Value”long?
StartedRuns
Section titled “ StartedRuns”The number of child runs started so far.
public int StartedRuns { get; }Property Value
Section titled “Property Value”Methods
Section titled “Methods”DescribeExhaustion()
Section titled “ DescribeExhaustion()”Produces a user-facing text describing the limit that was exceeded.
public string DescribeExhaustion()Returns
Section titled “Returns”Text stating which limit was exceeded.
Remarks
Section titled “Remarks”For agent delegation the text is returned to the model as a tool result; for a workflow step it is the message of the TraconRunBudgetExceededException that fails the run. Saying “budget exhausted” is not enough; unless the exceeded limit is named, the user cannot see which setting to raise.
DescribeModelCallExhaustion()
Section titled “ DescribeModelCallExhaustion()”Produces a user-facing text describing the token, cost, or time limit that cut a model call short mid-run.
public string DescribeModelCallExhaustion()Returns
Section titled “Returns”Remarks
Section titled “Remarks”Only called once AgentRunBudget.IsExhausted is true; the run-count limit does not apply here (see AgentRunBudget.IsExhausted).
RecordUsage(long)
Section titled “ RecordUsage(long)”Records the number of tokens spent into the budget.
public void RecordUsage(long tokens)Parameters
Section titled “Parameters”tokens long
The number of tokens to add. A negative value is ignored.
RecordUsage(long, decimal?)
Section titled “ RecordUsage(long, decimal?)”Records the tokens and cost spent in one model turn into the budget.
public void RecordUsage(long tokens, decimal? cost)Parameters
Section titled “Parameters”tokens long
The number of tokens to add. A negative value is ignored.
cost decimal?
The cost to add, or null when the turn’s price is undefined (PricingSource.Unknown) — nothing is added to AgentRunBudget.ConsumedCost in that case, so an installation with an unpriced model never trips a cost limit it cannot actually measure.
TryReserveRun()
Section titled “ TryReserveRun()”Reserves budget room for a new child run.
public bool TryReserveRun()Returns
Section titled “Returns”true if room was reserved; false if the token, cost, time, or count limit has been exceeded.
Remarks
Section titled “Remarks”The counter increments only when room is reserved. If a failed attempt incremented the counter, every new attempt in a tree that has hit its limit would keep growing the count, and the UI would show runs that never actually started.