@@ -5,6 +5,29 @@ import { hyphaWebsocketClient } from "hypha-rpc";
55import { ChatOptions , LLMApi , LLMConfig , RequestMessage } from "./api" ;
66import { ChatCompletionFinishReason , CompletionUsage } from "@mlc-ai/web-llm" ;
77
8+ // Simple authentication error detection
9+ const isAuthenticationError = ( error : any ) : boolean => {
10+ if ( ! error ) return false ;
11+
12+ let errorMessage = "Unknown error" ;
13+ if ( error && typeof error === "object" && "message" in error ) {
14+ errorMessage = String ( error . message ) ;
15+ } else if ( error && typeof error . toString === "function" ) {
16+ errorMessage = error . toString ( ) ;
17+ } else if ( typeof error === "string" ) {
18+ errorMessage = error ;
19+ }
20+
21+ return (
22+ errorMessage . includes ( "authentication" ) ||
23+ errorMessage . includes ( "token" ) ||
24+ errorMessage . includes ( "unauthorized" ) ||
25+ errorMessage . includes ( "Authentication failed" ) ||
26+ errorMessage . includes ( "403" ) ||
27+ errorMessage . includes ( "401" )
28+ ) ;
29+ } ;
30+
831export interface AgentConfig {
932 id : string ;
1033 name : string ;
@@ -49,7 +72,7 @@ export class HyphaAgentApi implements LLMApi {
4972 constructor (
5073 private serverUrl : string = "https://hypha.aicell.io" ,
5174 private serviceId : string = "hypha-agents/deno-app-engine" ,
52- private externalServer ?: any ,
75+ private getServerConnection ?: ( ) => Promise < any > ,
5376 ) { }
5477
5578 private getSavedToken ( ) : string | null {
@@ -69,11 +92,20 @@ export class HyphaAgentApi implements LLMApi {
6992 if ( this . isConnected ) return ;
7093
7194 try {
72- // Use external server if provided , otherwise create new connection
73- if ( this . externalServer ) {
74- log . info ( "[HyphaAgent] Using existing server connection..." ) ;
95+ // Use server connection provider if available , otherwise create new connection
96+ if ( this . getServerConnection ) {
97+ log . info ( "[HyphaAgent] Using server connection provider ..." ) ;
7598
76- this . server = this . externalServer ;
99+ try {
100+ this . server = await this . getServerConnection ( ) ;
101+ log . info (
102+ "[HyphaAgent] Server connection obtained:" ,
103+ typeof this . server ,
104+ ) ;
105+ } catch ( error ) {
106+ log . error ( "[HyphaAgent] Failed to get server connection:" , error ) ;
107+ throw error ;
108+ }
77109
78110 // Validate that the server has the required methods
79111 if ( ! this . server || typeof this . server . getService !== "function" ) {
@@ -96,11 +128,11 @@ export class HyphaAgentApi implements LLMApi {
96128 ) ;
97129 }
98130 } else {
99- log . warn (
100- "[HyphaAgent] No external server provided , creating new connection..." ,
131+ log . info (
132+ "[HyphaAgent] No server connection provider , creating new connection..." ,
101133 ) ;
102- log . warn (
103- "[HyphaAgent] This may cause 'Client already exists' errors if another connection exists " ,
134+ log . info (
135+ "[HyphaAgent] Note: This will create a separate connection which may cause performance overhead " ,
104136 ) ;
105137 // Get saved token from localStorage
106138 const token = this . getSavedToken ( ) ;
@@ -157,13 +189,14 @@ export class HyphaAgentApi implements LLMApi {
157189 log . error ( "[HyphaAgent] Failed to connect:" , error ) ;
158190
159191 // Check if this is an authentication error
160- const errorMessage =
161- error ?. message || error ?. toString ( ) || "Unknown error" ;
162- if (
163- errorMessage . includes ( "authentication" ) ||
164- errorMessage . includes ( "token" ) ||
165- errorMessage . includes ( "unauthorized" )
166- ) {
192+ if ( isAuthenticationError ( error ) ) {
193+ // Clear local storage to ensure consistency
194+ if ( typeof window !== "undefined" ) {
195+ localStorage . removeItem ( "token" ) ;
196+ localStorage . removeItem ( "tokenExpiry" ) ;
197+ localStorage . removeItem ( "user" ) ;
198+ }
199+
167200 throw new Error ( "Authentication failed. Please log in again." ) ;
168201 }
169202
@@ -179,23 +212,25 @@ export class HyphaAgentApi implements LLMApi {
179212 }
180213
181214 try {
182- // Check if agent already exists
183- if ( this . agentId ) {
184- try {
185- const existingAgents = await this . service . listAgents ( ) ;
186- const existingAgent = existingAgents . find (
187- ( a : AgentInfo ) => a . id === this . agentId ,
215+ // Check if agent already exists - match the full agent ID from config
216+ try {
217+ const existingAgents = await this . service . listAgents ( ) ;
218+ const existingAgent = existingAgents . find ( ( a : AgentInfo ) => {
219+ // Extract the agent part after the colon (e.g., "MZazLDPeIBxktE6fcgpRc@productive-martin-touch-upliftingly")
220+ const agentPart = a . id . includes ( ":" ) ? a . id . split ( ":" ) . pop ( ) : a . id ;
221+ // Match the full agent ID from config
222+ return agentPart === config . id ;
223+ } ) ;
224+ if ( existingAgent ) {
225+ log . info (
226+ "[HyphaAgent] Agent already exists, reusing:" ,
227+ existingAgent . id ,
188228 ) ;
189- if ( existingAgent ) {
190- log . info (
191- "[HyphaAgent] Agent already exists, reusing:" ,
192- this . agentId ,
193- ) ;
194- return existingAgent ;
195- }
196- } catch ( listError ) {
197- log . warn ( "[HyphaAgent] Failed to check existing agents:" , listError ) ;
229+ this . agentId = existingAgent . id ;
230+ return existingAgent ;
198231 }
232+ } catch ( listError ) {
233+ log . warn ( "[HyphaAgent] Failed to check existing agents:" , listError ) ;
199234 }
200235
201236 log . info ( "[HyphaAgent] Creating new agent:" , config . id ) ;
@@ -421,6 +456,22 @@ export class HyphaAgentApi implements LLMApi {
421456 return ;
422457 }
423458
459+ // Check for authentication errors
460+ if ( isAuthenticationError ( error ) ) {
461+ // Clear local storage on authentication failure
462+ if ( typeof window !== "undefined" ) {
463+ localStorage . removeItem ( "token" ) ;
464+ localStorage . removeItem ( "tokenExpiry" ) ;
465+ localStorage . removeItem ( "user" ) ;
466+ }
467+
468+ log . error ( "[HyphaAgent] Authentication error during chat:" , error ) ;
469+ options . onError ?.(
470+ new Error ( "Authentication failed. Please log in again." ) ,
471+ ) ;
472+ return ;
473+ }
474+
424475 log . error ( "[HyphaAgent] Chat error:" , error ) ;
425476 options . onError ?.( error ) ;
426477 } finally {
@@ -452,16 +503,20 @@ export class HyphaAgentApi implements LLMApi {
452503
453504 async disconnect ( ) : Promise < void > {
454505 try {
455- // Only disconnect if we created the connection (not using external server)
456- if ( this . server && "disconnect" in this . server && ! this . externalServer ) {
506+ // Only disconnect if we created the connection (not using server connection provider)
507+ if (
508+ this . server &&
509+ "disconnect" in this . server &&
510+ ! this . getServerConnection
511+ ) {
457512 await this . server . disconnect ( ) ;
458513 }
459514 } catch ( error ) {
460515 log . error ( "[HyphaAgent] Error disconnecting:" , error ) ;
461516 }
462517
463- // Reset state but don't clear external server
464- this . server = this . externalServer || null ;
518+ // Reset state
519+ this . server = null ;
465520 this . service = null ;
466521 this . isConnected = false ;
467522 this . agentId = null ;
@@ -473,13 +528,11 @@ export class HyphaAgentApi implements LLMApi {
473528 return this . getSavedToken ( ) !== null ;
474529 }
475530
476- // Set external server connection
477- setServer ( server : any ) : void {
478- this . externalServer = server ;
479- this . server = server ;
480- // Reset connection state to force re-initialization with new server
481- if ( server ) {
482- this . isConnected = false ;
483- }
531+ // Set server connection provider
532+ setServerConnectionProvider ( getServerConnection : ( ) => Promise < any > ) : void {
533+ this . getServerConnection = getServerConnection ;
534+ // Reset connection state to force re-initialization with new provider
535+ this . server = null ;
536+ this . isConnected = false ;
484537 }
485538}
0 commit comments