feat: rate limiting de tools por room en registry
Añade rate limiting de tool calls por room usando sliding window:
- tools/ratelimit.go: RateLimiter con sliding window per key (room),
Allow() para verificar/registrar llamadas, Cleanup() para limpiar
entries expiradas
- tools/registry.go: SetRateLimiter() y ExecuteForRoom() que verifica
el rate limit antes de ejecutar, logueando tool_rate_limited si excede
- internal/config/schema.go: ToolRateLimitCfg en SecurityCfg con
enabled, max_calls_per_min y cleanup_interval_s
- agents/runtime.go: inicializa rate limiter desde config y arranca
goroutine de cleanup periodico
- agents/commands.go: usa ExecuteForRoom en !tool command
Config YAML:
security:
tool_rate_limit:
enabled: true
max_calls_per_min: 10
Parte de issue 0019c (prompt injection hardening — rate limiting).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+21
-2
@@ -14,8 +14,9 @@ import (
|
||||
|
||||
// Registry holds available tools keyed by name.
|
||||
type Registry struct {
|
||||
tools map[string]Tool
|
||||
logger *slog.Logger
|
||||
tools map[string]Tool
|
||||
logger *slog.Logger
|
||||
rateLimiter *RateLimiter // nil when rate limiting is disabled
|
||||
}
|
||||
|
||||
// NewRegistry creates an empty registry.
|
||||
@@ -53,6 +54,24 @@ func (r *Registry) Len() int {
|
||||
return len(r.tools)
|
||||
}
|
||||
|
||||
// SetRateLimiter attaches a rate limiter to the registry.
|
||||
// When set, ExecuteForRoom checks the limit before running the tool.
|
||||
func (r *Registry) SetRateLimiter(rl *RateLimiter) {
|
||||
r.rateLimiter = rl
|
||||
}
|
||||
|
||||
// ExecuteForRoom is like Execute but checks the per-room rate limit first.
|
||||
// If the rate limit is exceeded, it returns an error result without executing.
|
||||
func (r *Registry) ExecuteForRoom(ctx context.Context, name, argsJSON, roomID string) Result {
|
||||
if r.rateLimiter != nil && roomID != "" {
|
||||
if !r.rateLimiter.Allow(roomID) {
|
||||
r.logger.Warn("tool_rate_limited", "tool", name, "room", roomID)
|
||||
return Result{Err: fmt.Errorf("rate limit exceeded for room %s: too many tool calls per minute", roomID)}
|
||||
}
|
||||
}
|
||||
return r.Execute(ctx, name, argsJSON)
|
||||
}
|
||||
|
||||
// Execute looks up a tool by name and runs it. Returns an error result if not found.
|
||||
func (r *Registry) Execute(ctx context.Context, name string, argsJSON string) Result {
|
||||
t, ok := r.tools[name]
|
||||
|
||||
Reference in New Issue
Block a user