agentgui 1.0.186 → 1.0.187

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.
@@ -107,11 +107,34 @@ class AgentRunner {
107
107
  const errorText = chunk.toString();
108
108
  console.error(`[${this.id}] stderr:`, errorText);
109
109
 
110
- const rateLimitMatch = errorText.match(/rate.?limit|429|too many requests|overloaded|throttl/i);
110
+ const rateLimitMatch = errorText.match(/rate.?limit|429|too many requests|overloaded|throttl|hit your limit/i);
111
111
  if (rateLimitMatch) {
112
112
  rateLimited = true;
113
113
  const retryMatch = errorText.match(/retry.?after[:\s]+(\d+)/i);
114
- if (retryMatch) retryAfterSec = parseInt(retryMatch[1], 10) || 60;
114
+ if (retryMatch) {
115
+ retryAfterSec = parseInt(retryMatch[1], 10) || 60;
116
+ } else {
117
+ const resetTimeMatch = errorText.match(/resets?\s+(?:at\s+)?(\d{1,2})(?::(\d{2}))?\s*(am|pm)?\s*\(?(UTC|[A-Z]{2,4})\)?/i);
118
+ if (resetTimeMatch) {
119
+ let hours = parseInt(resetTimeMatch[1], 10);
120
+ const minutes = resetTimeMatch[2] ? parseInt(resetTimeMatch[2], 10) : 0;
121
+ const period = resetTimeMatch[3]?.toLowerCase();
122
+ const tz = resetTimeMatch[4]?.toUpperCase() || 'UTC';
123
+
124
+ if (period === 'pm' && hours !== 12) hours += 12;
125
+ if (period === 'am' && hours === 12) hours = 0;
126
+
127
+ const now = new Date();
128
+ const resetTime = new Date(now);
129
+ resetTime.setUTCHours(hours, minutes, 0, 0);
130
+
131
+ if (resetTime <= now) {
132
+ resetTime.setUTCDate(resetTime.getUTCDate() + 1);
133
+ }
134
+
135
+ retryAfterSec = Math.max(60, Math.ceil((resetTime.getTime() - now.getTime()) / 1000));
136
+ }
137
+ }
115
138
  }
116
139
 
117
140
  if (onError) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.186",
3
+ "version": "1.0.187",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -1014,10 +1014,34 @@ async function processMessageWithStreaming(conversationId, messageId, sessionId,
1014
1014
  });
1015
1015
 
1016
1016
  if (isRateLimit) {
1017
+ const existingState = rateLimitState.get(conversationId) || {};
1018
+ const retryCount = (existingState.retryCount || 0) + 1;
1019
+ const maxRateLimitRetries = 3;
1020
+
1021
+ if (retryCount > maxRateLimitRetries) {
1022
+ debugLog(`[rate-limit] Conv ${conversationId} hit rate limit ${retryCount} times, giving up`);
1023
+ broadcastSync({
1024
+ type: 'streaming_error',
1025
+ sessionId,
1026
+ conversationId,
1027
+ error: `Rate limit exceeded after ${retryCount} attempts. Please try again later.`,
1028
+ recoverable: false,
1029
+ timestamp: Date.now()
1030
+ });
1031
+ const errorMessage = queries.createMessage(conversationId, 'assistant', `Error: Rate limit exceeded after ${retryCount} attempts. Please try again later.`);
1032
+ broadcastSync({
1033
+ type: 'message_created',
1034
+ conversationId,
1035
+ message: errorMessage,
1036
+ timestamp: Date.now()
1037
+ });
1038
+ return;
1039
+ }
1040
+
1017
1041
  const cooldownMs = (error.retryAfterSec || 60) * 1000;
1018
1042
  const retryAt = Date.now() + cooldownMs;
1019
- rateLimitState.set(conversationId, { retryAt, cooldownMs });
1020
- debugLog(`[rate-limit] Conv ${conversationId} hit rate limit, retry in ${cooldownMs}ms`);
1043
+ rateLimitState.set(conversationId, { retryAt, cooldownMs, retryCount });
1044
+ debugLog(`[rate-limit] Conv ${conversationId} hit rate limit (attempt ${retryCount}/${maxRateLimitRetries}), retry in ${cooldownMs}ms`);
1021
1045
 
1022
1046
  broadcastSync({
1023
1047
  type: 'rate_limit_hit',
@@ -1025,6 +1049,7 @@ async function processMessageWithStreaming(conversationId, messageId, sessionId,
1025
1049
  conversationId,
1026
1050
  retryAfterMs: cooldownMs,
1027
1051
  retryAt,
1052
+ retryCount,
1028
1053
  timestamp: Date.now()
1029
1054
  });
1030
1055
 
@@ -1032,7 +1057,7 @@ async function processMessageWithStreaming(conversationId, messageId, sessionId,
1032
1057
 
1033
1058
  setTimeout(() => {
1034
1059
  rateLimitState.delete(conversationId);
1035
- debugLog(`[rate-limit] Conv ${conversationId} cooldown expired, restarting`);
1060
+ debugLog(`[rate-limit] Conv ${conversationId} cooldown expired, restarting (attempt ${retryCount + 1})`);
1036
1061
  broadcastSync({
1037
1062
  type: 'rate_limit_clear',
1038
1063
  conversationId,