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.
- package/lib/claude-runner.js +25 -2
- package/package.json +1 -1
- package/server.js +28 -3
package/lib/claude-runner.js
CHANGED
|
@@ -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)
|
|
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
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,
|