@@ -298,6 +298,19 @@ function isContextLengthError(error: Error): boolean {
298298 ) ;
299299}
300300
301+ function isSessionError ( error : Error ) : boolean {
302+ const message = error . message . toLowerCase ( ) ;
303+ return (
304+ message . includes ( 'not connected' ) ||
305+ message . includes ( 'no session' ) ||
306+ message . includes ( 'initialization failed' ) ||
307+ message . includes ( 'session expired' ) ||
308+ message . includes ( 'session invalid' ) ||
309+ message . includes ( 'websocket' ) ||
310+ message . includes ( 'disconnected' )
311+ ) ;
312+ }
313+
301314function isTransientError ( error : Error ) : boolean {
302315 const message = error . message . toLowerCase ( ) ;
303316 const augmentError = error as AugmentAPIError ;
@@ -306,6 +319,9 @@ function isTransientError(error: Error): boolean {
306319 // 5xx server errors are transient
307320 if ( statusCode >= 500 && statusCode < 600 ) return true ;
308321
322+ // Session/connection errors from SDK are transient (can retry with new client)
323+ if ( isSessionError ( error ) ) return true ;
324+
309325 // Network-related errors
310326 if (
311327 message . includes ( 'network' ) ||
@@ -362,6 +378,22 @@ function createOpenAIError(error: Error): OpenAIError {
362378 } ;
363379 }
364380
381+ // Session/connection errors from SDK - provide specific guidance
382+ if ( isSessionError ( error ) ) {
383+ return {
384+ error : {
385+ message : `SDK session error: ${ error . message } ` ,
386+ type : 'server_error' ,
387+ code : 'connection_error' ,
388+ param : null ,
389+ suggestion :
390+ 'The Augment SDK connection was lost. This is usually temporary. ' +
391+ 'If the issue persists: 1) Run "auggie login" to refresh authentication, ' +
392+ '2) Restart the server, 3) Check your network connection.' ,
393+ } ,
394+ } ;
395+ }
396+
365397 if ( isTransientError ( error ) ) {
366398 return {
367399 error : {
@@ -710,6 +742,22 @@ function releaseAuggieClient(modelId: string, client: AuggieClient): void {
710742 }
711743}
712744
745+ // Discard a client without returning it to the pool (used when client has errors)
746+ function discardAuggieClient ( modelId : string , client : AuggieClient ) : void {
747+ const modelConfig = MODEL_MAP [ modelId ] ?? MODEL_MAP [ DEFAULT_MODEL ] ;
748+ if ( ! modelConfig ) return ;
749+ const auggieModel = modelConfig . auggie ;
750+ const pool = clientPools [ auggieModel ] ;
751+ if ( ! pool ) return ;
752+
753+ if ( pool . inUse . has ( client ) ) {
754+ pool . inUse . delete ( client ) ;
755+ }
756+ // Close the client without returning to pool
757+ void client . close ( ) ;
758+ console . log ( `Discarded faulty client for ${ auggieModel } (session/connection error)` ) ;
759+ }
760+
713761function getModels ( ) {
714762 const now = Math . floor ( Date . now ( ) / 1000 ) ;
715763 return Object . entries ( MODEL_MAP ) . map ( ( [ id , config ] ) => ( {
@@ -1284,6 +1332,24 @@ function createStreamCallback(res: ServerResponse, model: string, requestId: str
12841332 };
12851333}
12861334
1335+ // Check if response is an SDK error (JSON with error field)
1336+ function isSDKErrorResponse(response: string): { isError: boolean; message?: string } {
1337+ try {
1338+ const parsed = JSON.parse(response) as Record<string, unknown>;
1339+ const errorField = parsed['error'];
1340+ if (typeof errorField === 'string') {
1341+ return { isError: true, message: errorField };
1342+ }
1343+ if (errorField && typeof errorField === 'object') {
1344+ const errObj = errorField as Record<string, unknown>;
1345+ return { isError: true, message: (errObj['message'] as string) ?? String(errObj) };
1346+ }
1347+ } catch {
1348+ // Not JSON, so not an error response
1349+ }
1350+ return { isError: false };
1351+ }
1352+
12871353async function callAugmentAPIStreamingInternal(
12881354 prompt: string,
12891355 modelId: string,
@@ -1293,11 +1359,30 @@ async function callAugmentAPIStreamingInternal(
12931359): Promise<void> {
12941360 const client = await getAuggieClient(modelId);
12951361 client.onSessionUpdate(createStreamCallback(res, model, requestId));
1362+ let hasError = false;
1363+ let caughtError: Error | null = null;
12961364 try {
1297- await client.prompt(prompt);
1365+ const response = await client.prompt(prompt);
1366+ // Check if SDK returned an error as a response string (can happen even in streaming mode)
1367+ const errorCheck = isSDKErrorResponse(response);
1368+ if (errorCheck.isError) {
1369+ hasError = true;
1370+ caughtError = new Error(errorCheck.message ?? 'Unknown SDK error');
1371+ }
1372+ } catch (err) {
1373+ hasError = true;
1374+ caughtError = err as Error;
12981375 } finally {
12991376 client.onSessionUpdate(null);
1300- releaseAuggieClient(modelId, client);
1377+ // Discard client on session errors, otherwise return to pool
1378+ if (hasError && caughtError && isSessionError(caughtError)) {
1379+ discardAuggieClient(modelId, client);
1380+ } else {
1381+ releaseAuggieClient(modelId, client);
1382+ }
1383+ }
1384+ if (caughtError) {
1385+ throw caughtError;
13011386 }
13021387}
13031388
@@ -1317,11 +1402,34 @@ async function callAugmentAPIStreaming(
13171402
13181403async function callAugmentAPIInternal(prompt: string, modelId: string): Promise<string> {
13191404 const client = await getAuggieClient(modelId);
1405+ let hasError = false;
1406+ let caughtError: Error | null = null;
1407+ let result = '';
13201408 try {
1321- return await client.prompt(prompt);
1409+ const response = await client.prompt(prompt);
1410+ // Check if SDK returned an error as a response string
1411+ const errorCheck = isSDKErrorResponse(response);
1412+ if (errorCheck.isError) {
1413+ hasError = true;
1414+ caughtError = new Error(errorCheck.message ?? 'Unknown SDK error');
1415+ } else {
1416+ result = response;
1417+ }
1418+ } catch (err) {
1419+ hasError = true;
1420+ caughtError = err as Error;
13221421 } finally {
1323- releaseAuggieClient(modelId, client);
1422+ // Discard client on session errors, otherwise return to pool
1423+ if (hasError && caughtError && isSessionError(caughtError)) {
1424+ discardAuggieClient(modelId, client);
1425+ } else {
1426+ releaseAuggieClient(modelId, client);
1427+ }
1428+ }
1429+ if (caughtError) {
1430+ throw caughtError;
13241431 }
1432+ return result;
13251433}
13261434
13271435async function callAugmentAPI(prompt: string, modelId: string, requestId: string): Promise<string> {
0 commit comments