feat(license): LicenseUsageController GET /api/v1/admin/license/usage
Returns state, expiresAt/daysRemaining, lastValidatedAt, message
(LicenseMessageRenderer.forState), and a limits[] array where each
entry carries key/current/cap/source ("license" vs "default"). Adds
public AgentRegistryService.liveCount() so max_agents can be reported
from the in-memory registry.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -79,20 +79,20 @@ public class AgentRegistryService {
|
||||
// NEW registration — consult the cap. ConcurrentHashMap.compute propagates the
|
||||
// exception thrown here, so the controller advice (LicenseExceptionAdvice) maps
|
||||
// LicenseCapExceededException to 403 with the structured envelope.
|
||||
registerGuard.check(liveAgentCount());
|
||||
registerGuard.check(liveCount());
|
||||
log.info("Agent {} registered (name={}, application={}, env={})", id, name, application, environmentId);
|
||||
return newAgent;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Live-only agent count for license-cap enforcement.
|
||||
* STALE/DEAD/SHUTDOWN agents are excluded so the cap reflects the working fleet, not
|
||||
* historical residue. Re-registers of an existing agent revive it via the
|
||||
* Live-only agent count for license-cap enforcement and the {@code /admin/license/usage}
|
||||
* surface. STALE/DEAD/SHUTDOWN agents are excluded so the cap reflects the working fleet,
|
||||
* not historical residue. Re-registers of an existing agent revive it via the
|
||||
* {@code existing != null} branch in {@link #register}, so this count never double-counts.
|
||||
*/
|
||||
private long liveAgentCount() {
|
||||
return agents.values().stream().filter(a -> a.state() == AgentState.LIVE).count();
|
||||
public int liveCount() {
|
||||
return (int) agents.values().stream().filter(a -> a.state() == AgentState.LIVE).count();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user