#608: Ein wegen erschoepften Budgets abgelehnter Lauf hinterlaesst jetzt einen Beleg (Status BudgetExceeded) an Aufgabe und Verlauf; die Log-Warnung kommt einmal je Agent, Grenze und Tag. Die Kostenprognose zaehlt Ablehnungen nicht als Lauf und warnt, wenn die geplanten Aufgaben eines Agenten sein Tagesbudget uebersteigen (API + Verbrauchsansicht). #607: Passt schon der erste Treffer nicht in den Abruf, wird er gekuerzt (Anfang und Ende bleiben) statt ganz zu fehlen. remember weist auf gleichnamige Eintraege ohne Schluessel und auf Eintraege nahe der Abrufgrenze hin. Version 0.1.9. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -154,7 +154,7 @@ public sealed class AgentEngine : IAgentMessageRouter, Staging.IFrozenCallExecut
|
||||
return zu;
|
||||
|
||||
// Vor der ersten Anfrage prüfen — ein erschöpftes Budget soll gar nichts kosten.
|
||||
if (await CheckBudgetAsync(agentConfig, externalCt) is { } denied)
|
||||
if (await CheckBudgetAsync(agentConfig, source ?? AuditSource.Direct, taskId, externalCt) is { } denied)
|
||||
return denied;
|
||||
|
||||
using var lauf = TrackRun();
|
||||
@@ -425,7 +425,7 @@ public sealed class AgentEngine : IAgentMessageRouter, Staging.IFrozenCallExecut
|
||||
if (RefuseWhileShuttingDown(agentConfig) is { } zu)
|
||||
return zu;
|
||||
|
||||
if (await CheckBudgetAsync(agentConfig, externalCt) is { } denied)
|
||||
if (await CheckBudgetAsync(agentConfig, source, taskId, externalCt) is { } denied)
|
||||
return denied;
|
||||
|
||||
using var lauf = TrackRun();
|
||||
@@ -1600,7 +1600,8 @@ public sealed class AgentEngine : IAgentMessageRouter, Staging.IFrozenCallExecut
|
||||
/// Prüft das Tagesbudget. Gibt ein Ergebnis zurück, wenn der Lauf nicht stattfinden
|
||||
/// darf — sonst null.
|
||||
/// </summary>
|
||||
private async Task<AgentRunResult?> CheckBudgetAsync(AgentConfig agentConfig, CancellationToken ct)
|
||||
private async Task<AgentRunResult?> CheckBudgetAsync(
|
||||
AgentConfig agentConfig, string? source, string? taskId, CancellationToken ct)
|
||||
{
|
||||
if (_budgetGuard is null)
|
||||
return null;
|
||||
@@ -1609,17 +1610,38 @@ public sealed class AgentEngine : IAgentMessageRouter, Staging.IFrozenCallExecut
|
||||
if (status.IsAllowed)
|
||||
return null;
|
||||
|
||||
// #608: Ist ein Budget erschoepft, lehnt es jeden weiteren Lauf des Tages ab. Einmal je
|
||||
// Agent, Grenze und Tag als Warnung genuegt - danach steht jede Ablehnung als Beleg da.
|
||||
var logger = _loggerFactory.CreateLogger("ClawdDotNet.Core.Engine.Budget");
|
||||
logger.LogWarning("Lauf abgelehnt für {AgentId}: {Reason}", agentConfig.AgentId, status.Reason);
|
||||
var heute = DateOnly.FromDateTime(_clock.GetLocalNow().DateTime);
|
||||
var schluessel = agentConfig.AgentId + "|" + status.Limit;
|
||||
if (_budgetGewarnt.TryGetValue(schluessel, out var gewarnt) && gewarnt == heute)
|
||||
{
|
||||
logger.LogInformation("Lauf abgelehnt für {AgentId} (Aufgabe {TaskId}): {Reason}",
|
||||
agentConfig.AgentId, taskId ?? "-", status.Reason);
|
||||
}
|
||||
else
|
||||
{
|
||||
_budgetGewarnt[schluessel] = heute;
|
||||
logger.LogWarning("Lauf abgelehnt für {AgentId} (Aufgabe {TaskId}): {Reason} Weitere Ablehnungen heute stehen als Beleg im Verlauf.",
|
||||
agentConfig.AgentId, taskId ?? "-", status.Reason);
|
||||
}
|
||||
|
||||
var result = new AgentRunResult(
|
||||
agentConfig.AgentId, AgentRunStatus.BudgetExceeded,
|
||||
$"[Budget erschöpft] {status.Reason}", 0, 0, TimeSpan.Zero);
|
||||
|
||||
// #608: Ohne Beleg blieb die Ablehnung unsichtbar - Aufgabenkarte und Verlauf zeigten
|
||||
// weiter den letzten erfolgreichen Lauf, die Luecke fiel nur im Log auf.
|
||||
await RecordReceiptAsync(Guid.NewGuid().ToString("N"), agentConfig, result, source, taskId);
|
||||
|
||||
OnRunCompleted?.Invoke(agentConfig.Model, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>Welche Budgetgrenze je Agent zuletzt an welchem Tag als Warnung gemeldet wurde.</summary>
|
||||
private readonly System.Collections.Concurrent.ConcurrentDictionary<string, DateOnly> _budgetGewarnt = new();
|
||||
|
||||
/// <summary>
|
||||
/// Schreibt den Verbrauch eines Laufs fort. Fehler hierbei dürfen den Lauf nicht
|
||||
/// nachträglich scheitern lassen — die eigentliche Arbeit ist bereits getan.
|
||||
|
||||
Reference in New Issue
Block a user