sensorium-mcp 2.16.6 → 2.16.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,311 +0,0 @@
1
- /**
2
- * Rate Limiter — Coordinates API usage across concurrent agent sessions.
3
- *
4
- * Problem: When 4+ agents run simultaneously, each making GitHub/OpenAI/web
5
- * requests, external APIs start returning 429 (Too Many Requests).
6
- *
7
- * Solution: A shared in-process rate limiter that:
8
- * 1. Tracks API calls per service per sliding window
9
- * 2. Implements token-bucket rate limiting per service
10
- * 3. Provides an MCP tool for agents to check/acquire capacity
11
- * 4. Advises agents to back off when limits approach
12
- *
13
- * Architecture:
14
- * - ServiceBucket: token-bucket per service (GitHub, OpenAI, etc.)
15
- * - SessionTracker: per-session call counts for fair queuing
16
- * - acquireCapacity(): agents call this before making API calls
17
- * - getUsageStats(): dashboard visibility into rate state
18
- */
19
- const DEFAULT_SERVICES = {
20
- github: {
21
- maxRequests: 5000,
22
- windowMs: 60 * 60 * 1000, // 1 hour (GitHub API limit)
23
- burstSize: 30,
24
- refillRate: 1.4, // ~5000/hour
25
- description: "GitHub API",
26
- },
27
- openai: {
28
- maxRequests: 500,
29
- windowMs: 60 * 1000, // 1 minute
30
- burstSize: 20,
31
- refillRate: 8.3, // ~500/min
32
- description: "OpenAI API",
33
- },
34
- web: {
35
- maxRequests: 60,
36
- windowMs: 60 * 1000, // 1 minute
37
- burstSize: 10,
38
- refillRate: 1, // 60/min
39
- description: "Web requests",
40
- },
41
- telegram: {
42
- maxRequests: 30,
43
- windowMs: 1000, // 1 second (Telegram bot limit: 30 msg/s)
44
- burstSize: 30,
45
- refillRate: 30,
46
- description: "Telegram API",
47
- },
48
- };
49
- function createBucket(config) {
50
- return {
51
- tokens: config.burstSize,
52
- lastRefill: Date.now(),
53
- config,
54
- callLog: [],
55
- hourlyCallCount: 0,
56
- hourlyWindowStart: Date.now(),
57
- };
58
- }
59
- function refillBucket(bucket) {
60
- const now = Date.now();
61
- const elapsed = (now - bucket.lastRefill) / 1000;
62
- bucket.tokens = Math.min(bucket.config.burstSize, bucket.tokens + elapsed * bucket.config.refillRate);
63
- bucket.lastRefill = now;
64
- // Reset hourly counter if window expired
65
- if (now - bucket.hourlyWindowStart >= 60 * 60 * 1000) {
66
- bucket.hourlyCallCount = 0;
67
- bucket.hourlyWindowStart = now;
68
- }
69
- // Prune old call log entries — find cutoff via binary search instead of O(n) shift
70
- const windowStart = now - bucket.config.windowMs;
71
- let pruneIndex = 0;
72
- while (pruneIndex < bucket.callLog.length && bucket.callLog[pruneIndex] < windowStart) {
73
- pruneIndex++;
74
- }
75
- if (pruneIndex > 0) {
76
- bucket.callLog = bucket.callLog.slice(pruneIndex);
77
- }
78
- }
79
- class RateLimiter {
80
- buckets = new Map();
81
- sessions = new Map();
82
- serviceConfigs;
83
- constructor(customConfigs) {
84
- // Merge defaults with custom configs
85
- this.serviceConfigs = { ...DEFAULT_SERVICES };
86
- if (customConfigs) {
87
- for (const [service, overrides] of Object.entries(customConfigs)) {
88
- if (overrides) {
89
- this.serviceConfigs[service] = {
90
- ...(this.serviceConfigs[service] ?? DEFAULT_SERVICES.web),
91
- ...overrides,
92
- };
93
- }
94
- }
95
- }
96
- // Initialize buckets
97
- for (const [service, config] of Object.entries(this.serviceConfigs)) {
98
- this.buckets.set(service, createBucket(config));
99
- }
100
- }
101
- /**
102
- * Try to acquire capacity for an API call.
103
- * Call this BEFORE making an external API request.
104
- */
105
- acquire(service, mcpSessionId, threadId, count = 1) {
106
- // Ensure bucket exists (auto-create for unknown services)
107
- if (!this.buckets.has(service)) {
108
- const config = this.serviceConfigs[service] ?? { ...DEFAULT_SERVICES.web, description: service };
109
- this.serviceConfigs[service] = config;
110
- this.buckets.set(service, createBucket(config));
111
- }
112
- const bucket = this.buckets.get(service);
113
- refillBucket(bucket);
114
- // Validate count
115
- if (count <= 0)
116
- count = 1;
117
- const activeSessions = this.getActiveSessionCount();
118
- const usage = Math.min(1.0, bucket.callLog.length / bucket.config.maxRequests);
119
- // Fair share: if multiple sessions, each gets proportional quota
120
- const fairShare = activeSessions > 1 ? bucket.config.burstSize / activeSessions : bucket.config.burstSize;
121
- const sessionCalls = this.sessions.get(mcpSessionId)?.serviceCalls[service] ?? 0;
122
- // Check if this session is hogging the resource
123
- const isHogging = activeSessions > 1 && sessionCalls > fairShare * 1.5;
124
- if (bucket.tokens < count) {
125
- // Not enough tokens — DON'T track denied requests in session stats (bug fix)
126
- const waitMs = Math.ceil((count - bucket.tokens) / bucket.config.refillRate * 1000);
127
- return {
128
- allowed: false,
129
- waitMs,
130
- usage,
131
- activeSessions,
132
- message: `Rate limit reached for ${bucket.config.description}. ` +
133
- `${activeSessions} active agents sharing capacity. ` +
134
- `Wait ${Math.ceil(waitMs / 1000)}s before retrying.` +
135
- (isHogging ? " You're using more than your fair share — please slow down." : ""),
136
- };
137
- }
138
- // Only track session AFTER confirming the request is allowed
139
- this.touchSession(mcpSessionId, threadId, service, count);
140
- // Warning thresholds
141
- const warningLevel = usage > 0.8 ? "high"
142
- : usage > 0.5 ? "moderate"
143
- : "normal";
144
- // Consume tokens and track
145
- bucket.tokens -= count;
146
- const now = Date.now();
147
- for (let i = 0; i < count; i++) {
148
- bucket.callLog.push(now);
149
- }
150
- bucket.hourlyCallCount += count;
151
- let message = `OK — ${bucket.config.description}: ${Math.floor(bucket.tokens)}/${bucket.config.burstSize} tokens available`;
152
- if (activeSessions > 1) {
153
- message += `, ${activeSessions} agents sharing`;
154
- }
155
- if (warningLevel === "high") {
156
- message += ". ⚠️ Approaching rate limit — consider spacing out requests.";
157
- }
158
- else if (warningLevel === "moderate") {
159
- message += ". Usage moderate — monitoring.";
160
- }
161
- if (isHogging) {
162
- message += " ⚠️ You're using more than your fair share — other agents need capacity too.";
163
- }
164
- return {
165
- allowed: true,
166
- usage,
167
- activeSessions,
168
- message,
169
- };
170
- }
171
- /**
172
- * Record API calls that bypass the acquire() flow (e.g., implicit calls).
173
- * Use this for tracking only — doesn't block.
174
- */
175
- record(service, mcpSessionId, threadId, count = 1) {
176
- if (count <= 0)
177
- count = 1;
178
- if (!this.buckets.has(service))
179
- return;
180
- const bucket = this.buckets.get(service);
181
- refillBucket(bucket);
182
- const now = Date.now();
183
- for (let i = 0; i < count; i++) {
184
- bucket.callLog.push(now);
185
- }
186
- bucket.hourlyCallCount += count;
187
- // Consume tokens for record-only too — keeps stats consistent
188
- bucket.tokens = Math.max(0, bucket.tokens - count);
189
- this.touchSession(mcpSessionId, threadId, service, count);
190
- }
191
- /** Get comprehensive usage statistics for the dashboard. */
192
- getStats() {
193
- const now = Date.now();
194
- const services = [];
195
- for (const [service, bucket] of this.buckets) {
196
- refillBucket(bucket);
197
- const sessionBreakdown = [];
198
- for (const [sessionId, session] of this.sessions) {
199
- const calls = session.serviceCalls[service] ?? 0;
200
- if (calls > 0) {
201
- sessionBreakdown.push({
202
- mcpSessionId: sessionId,
203
- threadId: session.threadId,
204
- calls,
205
- });
206
- }
207
- }
208
- services.push({
209
- service,
210
- description: bucket.config.description,
211
- callsInWindow: bucket.callLog.length,
212
- maxPerWindow: bucket.config.maxRequests,
213
- usagePercent: Math.min(100, Math.round((bucket.callLog.length / bucket.config.maxRequests) * 100)),
214
- availableTokens: Math.floor(bucket.tokens),
215
- burstCapacity: bucket.config.burstSize,
216
- sessionBreakdown,
217
- });
218
- }
219
- // Total calls in last hour — use dedicated hourly counter (not callLog which
220
- // gets pruned to short windows for services like telegram/openai)
221
- let totalCallsLastHour = 0;
222
- for (const bucket of this.buckets.values()) {
223
- totalCallsLastHour += bucket.hourlyCallCount;
224
- }
225
- return {
226
- services,
227
- activeSessions: this.getActiveSessionCount(),
228
- totalCallsLastHour,
229
- };
230
- }
231
- /** Remove a session from tracking (called when session ends). */
232
- removeSession(mcpSessionId) {
233
- this.sessions.delete(mcpSessionId);
234
- }
235
- /** Reset all counters (useful for testing). */
236
- reset() {
237
- for (const [service, config] of Object.entries(this.serviceConfigs)) {
238
- this.buckets.set(service, createBucket(config));
239
- }
240
- this.sessions.clear();
241
- }
242
- // ── Private helpers ─────────────────────────────────────────────────────
243
- touchSession(mcpSessionId, threadId, service, count) {
244
- let session = this.sessions.get(mcpSessionId);
245
- if (!session) {
246
- session = {
247
- mcpSessionId,
248
- threadId,
249
- serviceCalls: {},
250
- lastActivity: Date.now(),
251
- totalCalls: 0,
252
- };
253
- this.sessions.set(mcpSessionId, session);
254
- }
255
- session.lastActivity = Date.now();
256
- session.serviceCalls[service] = (session.serviceCalls[service] ?? 0) + count;
257
- session.totalCalls += count;
258
- if (threadId !== undefined)
259
- session.threadId = threadId;
260
- }
261
- getActiveSessionCount() {
262
- const staleThreshold = Date.now() - 5 * 60 * 1000; // 5 min
263
- let active = 0;
264
- for (const session of this.sessions.values()) {
265
- if (session.lastActivity > staleThreshold)
266
- active++;
267
- }
268
- return active;
269
- }
270
- }
271
- // ─── Singleton ──────────────────────────────────────────────────────────────
272
- /** Global rate limiter instance — shared across all MCP sessions in-process. */
273
- export const rateLimiter = new RateLimiter(parseEnvOverrides());
274
- /**
275
- * Parse environment variable overrides for rate limits.
276
- * Format: RATE_LIMIT_{SERVICE}_{FIELD}=value
277
- * Example: RATE_LIMIT_GITHUB_MAX_REQUESTS=3000
278
- */
279
- function parseEnvOverrides() {
280
- const overrides = {};
281
- let hasOverrides = false;
282
- for (const [key, value] of Object.entries(process.env)) {
283
- const match = key.match(/^RATE_LIMIT_(\w+)_(MAX_REQUESTS|WINDOW_MS|BURST_SIZE|REFILL_RATE)$/i);
284
- if (match && value) {
285
- const service = match[1].toLowerCase();
286
- const field = match[2].toLowerCase();
287
- const num = Number(value);
288
- if (!Number.isFinite(num))
289
- continue;
290
- if (!overrides[service])
291
- overrides[service] = {};
292
- hasOverrides = true;
293
- switch (field) {
294
- case "max_requests":
295
- overrides[service].maxRequests = num;
296
- break;
297
- case "window_ms":
298
- overrides[service].windowMs = num;
299
- break;
300
- case "burst_size":
301
- overrides[service].burstSize = num;
302
- break;
303
- case "refill_rate":
304
- overrides[service].refillRate = num;
305
- break;
306
- }
307
- }
308
- }
309
- return hasOverrides ? overrides : undefined;
310
- }
311
- //# sourceMappingURL=rate-limiter.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"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"}