MICROSOFT AGENT FRAMEWORK · 0.16.0-rc.1
Demo340 — Loop Control
Native ChatClientAgent, without HarnessAgent, using the same Maf.Control. Default returns RepeatedCall and code 2 after one admitted attempt. This current entry has no naive/protected menu or unbounded loop.
Objectives
- Detect repeated requests and terminate a non-progressing agent loop.
Prepare the demo
Start at the root of the complete distribution built in Release; retain shared projects and files copied beside executables. Scripted transport or heuristic by default: no model, embeddings, secret or container required. --live explicitly selects common chat without cloud fallback.
dotnet build BaseTechnique.slnx -m:1 -c Release| Project | Role |
|---|---|
| demos/Demo340_LoopControl/Demo340.App.csproj | App |
| shared/Maf.Control/Maf.Control.csproj | Shared implementation |
Run from the root
dotnet run --project demos/Demo340_LoopControl/Demo340.App.csproj -c Release --no-buildProcedures and variants
Run without arguments to repeat read_ticket(42). Compare complete then changing. Read Middleware separately from ToolCall events.
public AIFunction CreateTool<T>(string name, string capability,
Func<T, CancellationToken, Task<string>> body)
{
return AIFunctionFactory.Create(async (T input, CancellationToken cancellationToken) =>
{
using var linked = CancellationTokenSource.CreateLinkedTokenSource(Token, cancellationToken);
linked.Token.ThrowIfCancellationRequested();
lock (sync)
{
CheckCancellation();
if (!capabilities.Contains(capability)) Halt("PermissionDenied", name, tools);
if (tools >= Limits.ToolCalls) Halt("ToolBudget", name, tools);
var key = name + ":" + Canonical(JsonSerializer.SerializeToElement(input));
var count = repetitions.GetValueOrDefault(key);
if (count >= Limits.Repetitions) Halt("RepeatedCall", name, count);
repetitions[key] = count + 1;
events.Add(new("ToolCall", name, ++tools));
}
var result = await body(input, linked.Token);
CheckCancellation();
return result;
Source code · Maf.Control · Folder
- shared/Maf.Control/Maf.Control.csproj
- demos/Demo330_BoundedHarness/Demo330.App.csproj
- demos/Demo340_LoopControl/Demo340.App.csproj
- demos/Demo380_RoleBasedTools/Demo380.App.csproj
dotnet run --project demos/Demo340_LoopControl/Demo340.App.csproj -c Release --no-build -- completedotnet run --project demos/Demo340_LoopControl/Demo340.App.csproj -c Release --no-build -- repeatdotnet run --project demos/Demo340_LoopControl/Demo340.App.csproj -c Release --no-build -- forbiddendotnet run --project demos/Demo340_LoopControl/Demo340.App.csproj -c Release --no-build -- budgetdotnet run --project demos/Demo340_LoopControl/Demo340.App.csproj -c Release --no-build -- changingdotnet run --project demos/Demo340_LoopControl/Demo340.App.csproj -c Release --no-build -- deadlinedotnet run --project demos/Demo340_LoopControl/Demo340.App.csproj -c Release --no-build -- incompleteResults, refusal and evidence
Native ChatClientAgent, without HarnessAgent, using the same Maf.Control. Default returns RepeatedCall and code 2 after one admitted attempt. This current entry has no naive/protected menu or unbounded loop.
Control limits
Scripted results verify actual orchestration and controls without qualifying a model or every attack. Counters are run-local; no durable idempotency or business write. Cancellation remains cooperative.
dotnet test tests/Maf.Control.Tests/Maf.Control.Tests.csproj -m:1 -c Release --no-build --no-restore