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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.570",
3
+ "version": "1.0.572",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
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;
@@ -272,7 +272,15 @@ class AgentGUIClient {
272
272
  if (window.conversationManager) {
273
273
  window.conversationManager.select(conversationId);
274
274
  } else {
275
- this.loadConversationMessages(conversationId).finally(() => {
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
- if (prevConversationId && prevConversationId !== conversationId) {
2564
- console.log('Resuming from previous conversation:', prevConversationId);
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(prevConversationId);
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
- if (prevConversationId && prevConversationId !== conversationId) {
2792
- console.log('Resuming from previous conversation due to error:', prevConversationId);
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(prevConversationId);
2806
+ await this.loadConversationMessages(fallbackConv);
2796
2807
  } catch (fallbackError) {
2797
- console.error('Failed to resume previous conversation:', fallbackError);
2808
+ console.error('Failed to resume fallback conversation:', fallbackError);
2798
2809
  this.showError('Failed to load conversation: ' + error.message);
2799
2810
  }
2800
2811
  } else {