Agenten-Kostendeckel: LoopGuard + PermissionGate aus ClawdDotNet uebernommen

- Neu PolyTrader.Core/Agents: AgentBudget (Steps/Tokens/Timeout), LoopGuard
  (thread-safe, AgentBudgetExceededException mit Kind), PermissionGate
  (Tool-Allow-List, null = alle erlaubt). Aus ClawdDotNet portiert, NICHT als
  Abhaengigkeit (.NET 10 vs 8).
- SupervisorAgent nutzt LoopGuard (Default-Steps = MaxIterations=8, rueckwaerts-
  kompatibel) + PermissionGate (Allow-List = angebotene Tools; nicht freigegebene
  Calls liefern Fehlertext statt Ausfuehrung). SupervisorProfile.Budget ueber-
  schreibt den Deckel. Abbruch graceful mit Grund (Steps/Tokens/Zeit).
- Tests: AgentGuardTests (LoopGuard/PermissionGate) + Token-Abbruch am Agenten.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-23 20:29:47 +02:00
co-authored by Claude Opus 4.8
parent 039bc240f8
commit bb103a578a
7 changed files with 275 additions and 8 deletions
@@ -101,6 +101,25 @@ namespace PolyTrader.Tests
Assert.Equal(SupervisorAgent.MaxIterations, result.ToolInvocations.Count);
}
[Fact]
public async Task Agent_aborts_when_token_budget_exceeded()
{
// Erste Antwort verbraucht bereits mehr Tokens als das Budget -> Abbruch VOR Tool-Ausführung.
var chat = new ScriptedChatClient(
new ChatResponse { PromptTokens = 80, CompletionTokens = 80,
ToolCalls = { new ToolCall("c1", "echo", "{}") } });
var agent = new SupervisorAgent(chat, RegistryWithEcho());
var profile = new SupervisorProfile("Knapp", "", null)
{
Budget = new PolyTrader.Core.Agents.AgentBudget { MaxTokens = 100, MaxSteps = 100 }
};
var result = await agent.AskAsync("x", profile: profile);
Assert.Contains("Token-Budget erschöpft", result.Answer);
Assert.Empty(result.ToolInvocations);
}
// ----- OpenRouter-Serialisierung (pur) -----
[Fact]