Skip to content

Python: Python + .NET: add AgentBudget for autonomous loop resource limits - #8994

Closed
Mark Licata (marklicata) wants to merge 3 commits into
microsoft:mainfrom
marklicata:agent-budget
Closed

Mark Licata (marklicata) wants to merge 3 commits into
microsoft:mainfrom
marklicata:agent-budget

Conversation

@marklicata

@marklicata Mark Licata (marklicata) commented Oct 2, 2026 •

Copy link
Copy Markdown

Motivation & Context

Closes #8862

Adds AgentBudget so operators can bound autonomous agent loops by token spend and
wall-clock time. Without explicit limits, a confused or looping agent can burn tokens
indefinitely or block a session open on a slow external tool — neither is safe for
production deployment.

Description & Review Guide

What are the major changes?

Python (agent_framework):

  • AgentBudget dataclass — max_tokens: int | None and max_duration: float | None; both optional, no defaults (operators must set them explicitly for autonomous sessions)
  • AgentLoopMiddleware — new budget: AgentBudget | None constructor arg; budget checks run before should_continue so an expensive judge is not called when a budget is exhausted
  • Token tracking — cumulative total_token_count per iteration from UsageDetails
  • Time tracking — time.monotonic() at loop start, checked per iteration
  • Exit reason stamped in AgentResponse.additional_properties["loop_exit_reason"]: "token_budget_exceeded" or "time_budget_exceeded" for budget stops (non-streaming only; streaming limitation documented), and "iteration_cap_reached" when max_iterations fires

.NET (Microsoft.Agents.AI):

  • LoopAgentOptions.MaxTokens (long?) and MaxDuration (TimeSpan?) — same semantics as Python
  • LoopAgent (non-streaming path) stamps LoopExitReason.TokenBudgetExceeded / TimeBudgetExceeded on budget stops and LoopExitReason.IterationCapReached when MaxIterations fires
  • LoopExitReason — new [Experimental] static class: AdditionalPropertiesKey, IterationCapReached, TokenBudgetExceeded, TimeBudgetExceeded (values match the Python strings)
  • PublicAPI.Unshipped.txt updated for all 5 target frameworks

What is the impact?

No breaking changes. AgentBudget is opt-in; loops without it behave identically to today.

Relationship to #8993: This PR is self-contained and can be reviewed and merged independently. It shares the loop_exit_reason key, iteration-cap stamping, and (.NET) the LoopExitReason class with #8993 (Signal Protocol); whichever merges second will take a merge from main that unions the exit-reason constants.

What do you want reviewers to focus on?

  • Budget check ordering: runs after pending-approval escape hatch, before should_continue
  • total_token_count fallback to input + output when total is absent (provider-dependent)
  • Streaming limitation: budget stops but cannot stamp AdditionalProperties in streaming mode

Related Issue

Closes #8862

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue.
  • This is not a breaking change.

Copilot AI balanced review requested due to automatic review settings October 2, 2026 23:45
@agent-framework-automation agent-framework-automation Bot added documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python .NET Usage: [Issues, PRs], Target: .Net labels Oct 2, 2026
@github-actions github-actions Bot changed the title Python + .NET: add AgentBudget for autonomous loop resource limits .NET: Python + .NET: add AgentBudget for autonomous loop resource limits Oct 2, 2026
@github-actions github-actions Bot changed the title .NET: Python + .NET: add AgentBudget for autonomous loop resource limits Python: Python + .NET: add AgentBudget for autonomous loop resource limits Oct 2, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Wall-clock limits do not interrupt hung work, and the current API baselines reference a missing .NET signal evaluator.

Review effort: Balanced
Findings: 4 High severity · 6 Medium severity · 3 Low severity

Open (13)
What changed in this PR

Adds cross-language token and duration limits for autonomous agent loops, alongside typed loop-exit metadata.

Changes:

  • Adds Python AgentBudget and .NET budget options.
  • Tracks cumulative token usage and elapsed time.
  • Adds exit reasons, public exports, API baselines, and tests.
File Description
python/​packages/​core/​tests/​core/​test_harness_loop.py Adds signal and budget tests.
python/​packages/​core/​agent_framework/​_harness/​_signals.py Defines signal parsing and exit reasons.
python/​packages/​core/​agent_framework/​_harness/​_loop.py Implements Python budget enforcement.
python/​packages/​core/​agent_framework/​__init__.pyi Exports new typed APIs.
python/​packages/​core/​agent_framework/​__init__.py Exports runtime APIs.
python/​CHANGELOG.md Adds a feature entry.
dotnet/​tests/​Microsoft.Agents.AI.UnitTests/​Harness/​Loop/​LoopAgentBudgetTests.cs Adds .NET budget tests.
dotnet/​src/​Microsoft.Agents.AI/​PublicAPI/​netstandard2.0/​PublicAPI.Unshipped.txt Updates netstandard API baseline.
dotnet/​src/​Microsoft.Agents.AI/​PublicAPI/​net9.0/​PublicAPI.Unshipped.txt Updates .NET 9 API baseline.
dotnet/​src/​Microsoft.Agents.AI/​PublicAPI/​net8.0/​PublicAPI.Unshipped.txt Updates .NET 8 API baseline.
dotnet/​src/​Microsoft.Agents.AI/​PublicAPI/​net472/​PublicAPI.Unshipped.txt Updates .NET Framework API baseline.
dotnet/​src/​Microsoft.Agents.AI/​PublicAPI/​net10.0/​PublicAPI.Unshipped.txt Updates .NET 10 API baseline.
dotnet/​src/​Microsoft.Agents.AI/​Harness/​Loop/​LoopExitReason.cs Adds typed exit-reason constants.
dotnet/​src/​Microsoft.Agents.AI/​Harness/​Loop/​LoopAgentOptions.cs Adds budget configuration properties.
dotnet/​src/​Microsoft.Agents.AI/​Harness/​Loop/​LoopAgent.cs Implements .NET budget enforcement.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +218 to +222
if (budgetStopwatch is not null && budgetStopwatch.Elapsed >= this._maxDuration)
{
AgentResponse budgetResult = this.BuildResult(response, transcript, aggregatedUsage);
(budgetResult.AdditionalProperties ??= new())[LoopExitReason.AdditionalPropertiesKey] = LoopExitReason.TimeBudgetExceeded;
return budgetResult;
Comment thread dotnet/src/Microsoft.Agents.AI/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt Outdated
Comment thread python/packages/core/agent_framework/_harness/_loop.py Outdated
Comment on lines +643 to +646
elapsed = time.monotonic() - budget_start
if self.budget.max_duration is not None and elapsed >= self.budget.max_duration:
budget_exit = "time_budget_exceeded"
break
Comment thread dotnet/src/Microsoft.Agents.AI/Harness/Loop/LoopAgent.cs
Comment thread python/packages/core/agent_framework/_harness/_signals.py Outdated
Comment on lines +173 to +174
# Fall back to additional_properties for framework-set reasons (e.g. iteration cap).
return response.additional_properties.get(LOOP_EXIT_REASON_KEY) or None
Comment thread python/CHANGELOG.md Outdated
Comment on lines +10 to +11
### Added
- **agent-framework-core**: Add `AgentBudget` with `max_tokens` and `max_duration` constraints for `AgentLoopMiddleware` autonomous loops; budget stops stamp `loop_exit_reason` in `AgentResponse.additional_properties`. Add `LoopExitReason.token_budget_exceeded` and `LoopExitReason.time_budget_exceeded`.
Comment on lines 449 to +450
"Agent",
"AgentBudget",
Comment thread python/packages/core/agent_framework/_harness/_loop.py
Adds token and wall-clock time budget constraints to AgentLoopMiddleware
(Python) and LoopAgent (.NET), enabling safe production autonomous loops.

AgentBudget (Python) / MaxTokens + MaxDuration (LoopAgentOptions, .NET):
- max_tokens / MaxTokens: stops the loop when cumulative LLM token spend
  exceeds the limit; counts total_token_count per iteration
- max_duration / MaxDuration: stops the loop when elapsed wall-clock time
  exceeds the limit; catches agents blocked on slow tools

Budget checks run before should_continue / LoopEvaluators so an expensive
judge predicate is not called after a budget is already exhausted.

New LoopExitReason values (both languages):
  token_budget_exceeded -- token cap fired
  time_budget_exceeded  -- wall-clock cap fired

Exit reason stamped in AgentResponse.AdditionalProperties["loop_exit_reason"]
on non-streaming runs. Streaming limitation documented as with the iteration cap.

Depends on microsoft#8993 (GT1 signal protocol) which introduces LoopExitReason.

Tests: 124 Python (7 new budget tests), .NET 4 new LoopAgentBudgetTests.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove signal-protocol pieces that belong to microsoft#8993 (Python _signals.py,
its exports and tests; .NET Completed/NeedInput/Cancelled exit reasons
and evaluator exit-reason propagation) and AsyncRequestBroker API
entries that belong to microsoft#8995. Iteration-cap stamping is kept since the
budget exit-reason contract and tests depend on it.

Also fix CI: restore PublicAPI BOMs, drop redundant System. qualifiers
(IDE0001/IDE0002), use the field keyword for validated options
(IDE0032), remove pyright-redundant None checks, and use a valid
positive MaxDuration in the time-budget test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@marklicata

Copy link
Copy Markdown
Author

Closing in favor of per-language PRs, as requested in review: Python in #9164, .NET in #9165. #9168 documents the one-language-per-PR expectation in CONTRIBUTING.md.

This branch was successfully deployed

1 active and 1 inactive deployments
github-app-auth — 57a59a90 Deployed Oct 6, 2026 by marklicata via add_label #24570
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs .NET Usage: [Issues, PRs], Target: .Net python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add token and wall-clock budget enforcement to AgentLoopMiddleware

2 participants