.NET API
AgentRunBudget
Tracon.Abstractions.dllA run budget shared across an entire call tree.
public sealed class AgentRunBudgetInheritance
Section titled “Inheritance”Inherited Members
Section titled “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.
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.
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”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”The text is returned to the model as a tool result. 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.