AzureAICommunity.Agent.Middleware.ToolLimitMiddleware
1.0.0
dotnet add package AzureAICommunity.Agent.Middleware.ToolLimitMiddleware --version 1.0.0
NuGet\Install-Package AzureAICommunity.Agent.Middleware.ToolLimitMiddleware -Version 1.0.0
<PackageReference Include="AzureAICommunity.Agent.Middleware.ToolLimitMiddleware" Version="1.0.0" />
<PackageVersion Include="AzureAICommunity.Agent.Middleware.ToolLimitMiddleware" Version="1.0.0" />
<PackageReference Include="AzureAICommunity.Agent.Middleware.ToolLimitMiddleware" />
paket add AzureAICommunity.Agent.Middleware.ToolLimitMiddleware --version 1.0.0
#r "nuget: AzureAICommunity.Agent.Middleware.ToolLimitMiddleware, 1.0.0"
#:package AzureAICommunity.Agent.Middleware.ToolLimitMiddleware@1.0.0
#addin nuget:?package=AzureAICommunity.Agent.Middleware.ToolLimitMiddleware&version=1.0.0
#tool nuget:?package=AzureAICommunity.Agent.Middleware.ToolLimitMiddleware&version=1.0.0
<div align="center">
๐ ๏ธ AzureAICommunity - Agent - Tool Limit Middleware
Prevent runaway tool calls by enforcing global and per-tool call limits across every AI agent completion.
Getting Started ยท Per-Tool Limits ยท Inspect Usage ยท How It Works ยท Contributing
</div>
Overview
AzureAICommunity.Agent.Middleware.ToolLimitMiddleware is a lightweight guard layer for AI agent pipelines built on Microsoft.Extensions.AI. During each completion it tracks every FunctionCallContent emitted by the model and silently suppresses any calls that breach a configurable global cap or an optional per-tool cap. When calls are suppressed, a user-role message is appended to the conversation so the model is aware that limits have been reached.
โจ Features
| Feature | |
|---|---|
| ๐ข | Global call cap โ limits the total number of tool invocations in a session |
| ๐ง | Per-tool limits โ set independent ceilings for individual tool names |
| ๐ | Streaming support โ works with both GetResponseAsync and GetStreamingResponseAsync |
| ๐คซ | Silent suppression โ over-limit calls are removed; no exception is thrown |
| ๐ฌ | Model notification โ a user message informs the model when calls have been removed |
| ๐ | Usage introspection โ GetCurrentUsage() returns attempted vs allowed counts per tool, plus configured limits |
| ๐ | Resettable โ Reset() clears counters for a fresh session |
| ๐ | MEA integration โ drops directly into any Microsoft.Extensions.AI pipeline via UseToolLimit() |
๐ฆ Installation
dotnet add package AzureAICommunity.Agent.Middleware.ToolLimitMiddleware
๐ Quick Start
using System.ComponentModel;
using AzureAICommunityAgent.Middleware.ToolLimiting;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OllamaSharp;
IChatClient ollamaClient = new OllamaApiClient("http://localhost:11434/", "llama3.2");
var weatherTool = AIFunctionFactory.Create(
([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15\u00b0C.",
"GetWeather");
IChatClient client = ollamaClient
.AsBuilder()
.UseToolLimit(new ToolLimits { GlobalMax = 5 })
.Build();
AIAgent agent = new ChatClientAgent(client,
instructions: "You are a helpful assistant with access to a weather tool.",
tools: [weatherTool]);
var response = await agent.RunAsync("What is the weather like in Amsterdam?");
Console.WriteLine(response.Text);
๐ง Per-Tool Limits
In addition to the global cap, you can restrict individual tools independently:
var weatherTool = AIFunctionFactory.Create(/* ... */, "GetWeather");
var youtubeTool = AIFunctionFactory.Create(/* ... */, "SearchVideos");
IChatClient client = ollamaClient
.AsBuilder()
.UseToolLimit(new ToolLimits
{
GlobalMax = 10,
PerToolMax = new Dictionary<string, int>
{
["GetWeather"] = 3,
["SearchVideos"] = 2
}
})
.Build();
AIAgent agent = new ChatClientAgent(client,
instructions: "You are a helpful assistant.",
tools: [weatherTool, youtubeTool]);
Any call to GetWeather beyond 3, or to SearchVideos beyond 2, is silently removed โ even if the global limit has not been reached.
๐ Inspect Usage
After building the client with UseToolLimit, retrieve the tracker via GetService<IToolLimitTracker>():
IChatClient client = ollamaClient
.AsBuilder()
.UseToolLimit(new ToolLimits
{
GlobalMax = 5,
PerToolMax = new Dictionary<string, int> { ["GetWeather"] = 3 }
})
.Build();
// Run the agent
AIAgent agent = new ChatClientAgent(client,
instructions: "You are a helpful assistant with access to a weather tool.",
tools: [weatherTool]);
var response = await agent.RunAsync("What is the weather like in Amsterdam?");
Console.WriteLine(response.Text);
// Retrieve the tracker from the pipeline
var tracker = client.GetService<IToolLimitTracker>();
ToolUsageState usage = tracker!.GetCurrentUsage();
Console.WriteLine($"Total allowed calls: {usage.TotalCalls} / {usage.GlobalLimit}");
Console.WriteLine("Per-tool usage (attempted / allowed / limit):");
foreach (var (tool, attempted) in usage.PerTool)
{
usage.PerToolAllowed.TryGetValue(tool, out var allowed);
usage.PerToolLimits.TryGetValue(tool, out var perMax);
var limitText = perMax > 0 ? $" / {perMax}" : string.Empty;
Console.WriteLine($" {tool}: attempted={attempted} allowed={allowed}{limitText}");
}
// Reset counters for a new session
tracker.Reset();
Example output:
Total allowed calls: 3 / 5
Per-tool usage (attempted / allowed / limit):
GetWeather: attempted=5 allowed=3 / 3
๐ Constructor Reference
public ToolLimitMiddleware(
IChatClient innerClient, // Inner chat client to delegate to
ToolLimits? limits = null // Limits configuration (defaults: GlobalMax = 10, no per-tool limits)
)
Extension method
builder.UseToolLimit(new ToolLimits
{
GlobalMax = 10,
PerToolMax = new Dictionary<string, int> { ["GetWeather"] = 3, ["SearchVideos"] = 2 }
});
๐ Type Reference
| Type | Description |
|---|---|
IToolLimitTracker |
Public interface for reading usage and resetting counters |
ToolLimits |
Configuration object: GlobalMax (default 10), PerToolMax (per-tool ceilings) |
ToolUsageState |
Snapshot from GetCurrentUsage() โ see table below |
ToolLimitMiddlewareExtensions |
UseToolLimit(ToolLimits?) extension for ChatClientBuilder |
ToolUsageState properties
| Property | Type | Description |
|---|---|---|
TotalCalls |
int |
Number of tool calls actually allowed through |
GlobalLimit |
int |
Configured GlobalMax value |
PerTool |
Dictionary<string, int> |
All attempted calls per tool, including blocked |
PerToolAllowed |
Dictionary<string, int> |
Calls that were allowed per tool |
PerToolLimits |
Dictionary<string, int> |
Configured PerToolMax ceilings |
๐ค Contributing
Contributions are welcome! Please open an issue to discuss what you'd like to change before submitting a pull request.
๐ Repository: https://github.com/rvinothrajendran/AgentFramework
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Commit your changes (
git commit -m 'Add my feature') - Push to the branch (
git push origin feature/my-feature) - Open a Pull Request
๐ค Author
Built and maintained by Vinoth Rajendran.
- ๐ GitHub: github.com/rvinothrajendran โ follow for more projects!
- ๐บ YouTube: youtube.com/@VinothRajendran โ subscribe for tutorials and demos!
- ๐ผ LinkedIn: linkedin.com/in/rvinothrajendran โ let's connect!
๐ License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Agents.AI (>= 1.1.0)
- Microsoft.Extensions.AI (>= 10.4.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 184 | 4/27/2026 |