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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AzureAICommunity.Agent.Middleware.ToolLimitMiddleware" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AzureAICommunity.Agent.Middleware.ToolLimitMiddleware" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="AzureAICommunity.Agent.Middleware.ToolLimitMiddleware" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add AzureAICommunity.Agent.Middleware.ToolLimitMiddleware --version 1.0.0
                    
#r "nuget: AzureAICommunity.Agent.Middleware.ToolLimitMiddleware, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package AzureAICommunity.Agent.Middleware.ToolLimitMiddleware@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=AzureAICommunity.Agent.Middleware.ToolLimitMiddleware&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=AzureAICommunity.Agent.Middleware.ToolLimitMiddleware&version=1.0.0
                    
Install as a Cake Tool

<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.

NuGet Version NuGet Downloads License .NET GitHub Repo GitHub Follow YouTube Channel YouTube Subscribers LinkedIn

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

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/my-feature)
  3. Commit your changes (git commit -m 'Add my feature')
  4. Push to the branch (git push origin feature/my-feature)
  5. Open a Pull Request

๐Ÿ‘ค Author

Built and maintained by Vinoth Rajendran.


๐Ÿ“„ License

MIT

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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