feat: import agents_and_robots platform as unibots (Matrix-out, unibus transport)
Reemplaza el scaffold del echobot por la plataforma completa de bots traida desde ~/DataProyects/Github/agents_and_robots tras la operacion Matrix-out: los bots ya no hablan por Matrix sino por el bus unibus (modelo todo-rooms + E2E via shell/transportunibus sobre github.com/enmanuel/unibus/pkg/client). - go.mod: replace de unibus -> ../unibus y de fn-registry -> ../../../.. (paths relativos reajustados a la nueva ubicacion dentro de fn_registry). - app.md: bump a 0.2.0, descripcion + arquitectura + comandos + gotchas reales. - modulo Go conservado como github.com/enmanuel/agents (sin reescribir imports). agents_and_robots queda archivado como museo de la era Matrix.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RateLimiter tracks tool call counts per key (typically roomID) using a
|
||||
// sliding window. It is safe for concurrent use.
|
||||
type RateLimiter struct {
|
||||
maxCalls int
|
||||
window time.Duration
|
||||
mu sync.Mutex
|
||||
buckets map[string][]time.Time
|
||||
}
|
||||
|
||||
// NewRateLimiter creates a rate limiter that allows maxCalls per window per key.
|
||||
func NewRateLimiter(maxCalls int, window time.Duration) *RateLimiter {
|
||||
return &RateLimiter{
|
||||
maxCalls: maxCalls,
|
||||
window: window,
|
||||
buckets: make(map[string][]time.Time),
|
||||
}
|
||||
}
|
||||
|
||||
// Allow checks whether a call for the given key is within the rate limit.
|
||||
// If allowed, it records the call and returns true. Otherwise returns false.
|
||||
func (rl *RateLimiter) Allow(key string) bool {
|
||||
rl.mu.Lock()
|
||||
defer rl.mu.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
cutoff := now.Add(-rl.window)
|
||||
|
||||
// Trim expired entries
|
||||
calls := rl.buckets[key]
|
||||
start := 0
|
||||
for start < len(calls) && calls[start].Before(cutoff) {
|
||||
start++
|
||||
}
|
||||
calls = calls[start:]
|
||||
|
||||
if len(calls) >= rl.maxCalls {
|
||||
rl.buckets[key] = calls
|
||||
return false
|
||||
}
|
||||
|
||||
rl.buckets[key] = append(calls, now)
|
||||
return true
|
||||
}
|
||||
|
||||
// Cleanup removes stale entries for keys that have no recent calls.
|
||||
// Should be called periodically to prevent memory growth.
|
||||
func (rl *RateLimiter) Cleanup() {
|
||||
rl.mu.Lock()
|
||||
defer rl.mu.Unlock()
|
||||
|
||||
cutoff := time.Now().Add(-rl.window)
|
||||
for key, calls := range rl.buckets {
|
||||
start := 0
|
||||
for start < len(calls) && calls[start].Before(cutoff) {
|
||||
start++
|
||||
}
|
||||
if start >= len(calls) {
|
||||
delete(rl.buckets, key)
|
||||
} else {
|
||||
rl.buckets[key] = calls[start:]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user