agentgui 1.0.570 → 1.0.572
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 +16 -0
- package/package.json +1 -1
- package/server.js +29 -1
- package/static/js/client.js +21 -10
package/lib/claude-runner.js
CHANGED
|
@@ -105,6 +105,8 @@ class AgentRunner {
|
|
|
105
105
|
let sessionId = null;
|
|
106
106
|
let rateLimited = false;
|
|
107
107
|
let retryAfterSec = 60;
|
|
108
|
+
let authError = false;
|
|
109
|
+
let authErrorMessage = '';
|
|
108
110
|
|
|
109
111
|
const timeoutHandle = setTimeout(() => {
|
|
110
112
|
timedOut = true;
|
|
@@ -151,6 +153,12 @@ class AgentRunner {
|
|
|
151
153
|
const errorText = chunk.toString();
|
|
152
154
|
console.error(`[${this.id}] stderr:`, errorText);
|
|
153
155
|
|
|
156
|
+
const authMatch = errorText.match(/401|unauthorized|invalid.*auth|invalid.*token|auth.*failed|permission denied|access denied/i);
|
|
157
|
+
if (authMatch) {
|
|
158
|
+
authError = true;
|
|
159
|
+
authErrorMessage = errorText.trim();
|
|
160
|
+
}
|
|
161
|
+
|
|
154
162
|
const rateLimitMatch = errorText.match(/rate.?limit|429|too many requests|overloaded|throttl|hit your limit/i);
|
|
155
163
|
if (rateLimitMatch) {
|
|
156
164
|
rateLimited = true;
|
|
@@ -190,6 +198,14 @@ class AgentRunner {
|
|
|
190
198
|
clearTimeout(timeoutHandle);
|
|
191
199
|
if (timedOut) return;
|
|
192
200
|
|
|
201
|
+
if (authError) {
|
|
202
|
+
const err = new Error(`Authentication failed: ${authErrorMessage || 'Invalid credentials or unauthorized access'}`);
|
|
203
|
+
err.authError = true;
|
|
204
|
+
err.nonRetryable = true;
|
|
205
|
+
reject(err);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
193
209
|
if (rateLimited) {
|
|
194
210
|
const err = new Error(`Rate limited - retry after ${retryAfterSec}s`);
|
|
195
211
|
err.rateLimited = true;
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -22,7 +22,7 @@ import { register as registerConvHandlers } from './lib/ws-handlers-conv.js';
|
|
|
22
22
|
import { register as registerSessionHandlers } from './lib/ws-handlers-session.js';
|
|
23
23
|
import { register as registerRunHandlers } from './lib/ws-handlers-run.js';
|
|
24
24
|
import { register as registerUtilHandlers } from './lib/ws-handlers-util.js';
|
|
25
|
-
import { startAll as startACPTools, stopAll as stopACPTools, getStatus as getACPStatus, getPort as getACPPort, queryModels as queryACPModels, touch as touchACP } from './lib/acp-manager.js';
|
|
25
|
+
import { startAll as startACPTools, stopAll as stopACPTools, getStatus as getACPStatus, getPort as getACPPort, ensureRunning, queryModels as queryACPModels, touch as touchACP } from './lib/acp-manager.js';
|
|
26
26
|
import { installGMAgentConfigs } from './lib/gm-agent-configs.js';
|
|
27
27
|
import * as toolManager from './lib/tool-manager.js';
|
|
28
28
|
import { pm2Manager } from './lib/pm2-manager.js';
|
|
@@ -480,6 +480,7 @@ async function getModelsForAgent(agentId) {
|
|
|
480
480
|
} else {
|
|
481
481
|
const agent = discoveredAgents.find(a => a.id === agentId);
|
|
482
482
|
if (agent?.protocol === 'acp') {
|
|
483
|
+
await ensureRunning(agentId);
|
|
483
484
|
try { models = await queryACPModels(agentId); } catch (_) {}
|
|
484
485
|
}
|
|
485
486
|
}
|
|
@@ -3862,6 +3863,9 @@ async function processMessageWithStreaming(conversationId, messageId, sessionId,
|
|
|
3862
3863
|
return;
|
|
3863
3864
|
}
|
|
3864
3865
|
|
|
3866
|
+
const isAuthError = error.authError || error.nonRetryable ||
|
|
3867
|
+
/401|unauthorized|invalid.*auth|invalid.*token|auth.*failed|permission denied|access denied/i.test(error.message);
|
|
3868
|
+
|
|
3865
3869
|
const isRateLimit = error.rateLimited ||
|
|
3866
3870
|
/rate.?limit|429|too many requests|overloaded|throttl/i.test(error.message);
|
|
3867
3871
|
|
|
@@ -3871,6 +3875,30 @@ async function processMessageWithStreaming(conversationId, messageId, sessionId,
|
|
|
3871
3875
|
completed_at: Date.now()
|
|
3872
3876
|
});
|
|
3873
3877
|
|
|
3878
|
+
if (isAuthError) {
|
|
3879
|
+
debugLog(`[auth-error] Auth error for conv ${conversationId}: ${error.message}`);
|
|
3880
|
+
broadcastSync({
|
|
3881
|
+
type: 'streaming_error',
|
|
3882
|
+
sessionId,
|
|
3883
|
+
conversationId,
|
|
3884
|
+
error: `Authentication failed: ${error.message}. Please check your API credentials.`,
|
|
3885
|
+
recoverable: false,
|
|
3886
|
+
isAuthError: true,
|
|
3887
|
+
timestamp: Date.now()
|
|
3888
|
+
});
|
|
3889
|
+
const errorMessage = queries.createMessage(conversationId, 'assistant', `Error: Authentication failed. ${error.message}. Please update your credentials and try again.`);
|
|
3890
|
+
broadcastSync({
|
|
3891
|
+
type: 'message_created',
|
|
3892
|
+
conversationId,
|
|
3893
|
+
message: errorMessage,
|
|
3894
|
+
timestamp: Date.now()
|
|
3895
|
+
});
|
|
3896
|
+
queries.setIsStreaming(conversationId, false);
|
|
3897
|
+
batcher.drain();
|
|
3898
|
+
activeExecutions.delete(conversationId);
|
|
3899
|
+
return;
|
|
3900
|
+
}
|
|
3901
|
+
|
|
3874
3902
|
if (isRateLimit) {
|
|
3875
3903
|
const existingState = rateLimitState.get(conversationId) || {};
|
|
3876
3904
|
const retryCount = (existingState.retryCount || 0) + 1;
|
package/static/js/client.js
CHANGED
|
@@ -272,7 +272,15 @@ class AgentGUIClient {
|
|
|
272
272
|
if (window.conversationManager) {
|
|
273
273
|
window.conversationManager.select(conversationId);
|
|
274
274
|
} else {
|
|
275
|
-
this.loadConversationMessages(conversationId).
|
|
275
|
+
this.loadConversationMessages(conversationId).catch((err) => {
|
|
276
|
+
console.warn('Failed to restore conversation from URL, loading latest instead:', err);
|
|
277
|
+
// If the URL conversation doesn't exist, try loading the most recent conversation
|
|
278
|
+
if (this.state.conversations && this.state.conversations.length > 0) {
|
|
279
|
+
const latestConv = this.state.conversations[0];
|
|
280
|
+
console.log('Loading latest conversation instead:', latestConv.id);
|
|
281
|
+
return this.loadConversationMessages(latestConv.id);
|
|
282
|
+
}
|
|
283
|
+
}).finally(() => {
|
|
276
284
|
this._isLoadingConversation = false;
|
|
277
285
|
});
|
|
278
286
|
}
|
|
@@ -2489,6 +2497,7 @@ class AgentGUIClient {
|
|
|
2489
2497
|
const convSignal = this._previousConvAbort.signal;
|
|
2490
2498
|
|
|
2491
2499
|
const prevConversationId = this.state.currentConversation?.id;
|
|
2500
|
+
const availableFallback = this.state.conversations?.find(c => c.id !== conversationId) || null;
|
|
2492
2501
|
this.cacheCurrentConversation();
|
|
2493
2502
|
this.stopChunkPolling();
|
|
2494
2503
|
this.removeScrollUpDetection();
|
|
@@ -2559,11 +2568,12 @@ class AgentGUIClient {
|
|
|
2559
2568
|
console.warn('Conversation no longer exists:', conversationId);
|
|
2560
2569
|
this.state.currentConversation = null;
|
|
2561
2570
|
if (window.conversationManager) window.conversationManager.loadConversations();
|
|
2562
|
-
// Resume from last successful conversation if available
|
|
2563
|
-
|
|
2564
|
-
|
|
2571
|
+
// Resume from last successful conversation if available, or fall back to any available conversation
|
|
2572
|
+
const fallbackConv = prevConversationId ? prevConversationId : availableFallback?.id;
|
|
2573
|
+
if (fallbackConv && fallbackConv !== conversationId) {
|
|
2574
|
+
console.log('Resuming from fallback conversation:', fallbackConv);
|
|
2565
2575
|
this.showError('Conversation not found. Resuming previous conversation.');
|
|
2566
|
-
await this.loadConversationMessages(
|
|
2576
|
+
await this.loadConversationMessages(fallbackConv);
|
|
2567
2577
|
} else {
|
|
2568
2578
|
const outputEl = document.getElementById('output');
|
|
2569
2579
|
if (outputEl) outputEl.innerHTML = '<p class="text-secondary" style="padding:2rem;text-align:center">Conversation not found. It may have been lost during a server restart.</p>';
|
|
@@ -2787,14 +2797,15 @@ class AgentGUIClient {
|
|
|
2787
2797
|
} catch (error) {
|
|
2788
2798
|
if (error.name === 'AbortError') return;
|
|
2789
2799
|
console.error('Failed to load conversation messages:', error);
|
|
2790
|
-
// Resume from last successful conversation if available
|
|
2791
|
-
|
|
2792
|
-
|
|
2800
|
+
// Resume from last successful conversation if available, or fall back to any available conversation
|
|
2801
|
+
const fallbackConv = prevConversationId ? prevConversationId : availableFallback?.id;
|
|
2802
|
+
if (fallbackConv && fallbackConv !== conversationId) {
|
|
2803
|
+
console.log('Resuming from fallback conversation due to error:', fallbackConv);
|
|
2793
2804
|
this.showError('Failed to load conversation. Resuming previous conversation.');
|
|
2794
2805
|
try {
|
|
2795
|
-
await this.loadConversationMessages(
|
|
2806
|
+
await this.loadConversationMessages(fallbackConv);
|
|
2796
2807
|
} catch (fallbackError) {
|
|
2797
|
-
console.error('Failed to resume
|
|
2808
|
+
console.error('Failed to resume fallback conversation:', fallbackError);
|
|
2798
2809
|
this.showError('Failed to load conversation: ' + error.message);
|
|
2799
2810
|
}
|
|
2800
2811
|
} else {
|