@@ -147,7 +147,7 @@ interface ClientPool {
147147}
148148
149149interface AuggieSDK {
150- create : ( options : { model ?: string ; apiKey ?: string ; apiUrl ?: string } ) => Promise < AuggieClient > ;
150+ create : ( options : { model ?: string ; apiKey ?: string ; apiUrl ?: string ; workspaceRoot ?: string } ) = > Promise < AuggieClient > ;
151151}
152152
153153// Configuration
@@ -657,44 +657,56 @@ async function initAuggie(): Promise<void> {
657657 }
658658}
659659
660- async function createAuggieClient ( auggieModel : string ) : Promise < AuggieClient > {
660+ async function createAuggieClient ( auggieModel : string , workspaceRoot ?: string ) : Promise < AuggieClient > {
661661 await initAuggie ( ) ;
662662 if ( ! AuggieClass ) {
663663 throw new Error ( 'Auggie SDK not initialized' ) ;
664664 }
665665 const sess = await loadSession ( ) ;
666- debugLog ( 'Creating Auggie Client' , { model : auggieModel , apiUrl : sess . tenantURL } ) ;
666+ // Use provided workspace or fall back to home directory
667+ const workspace = workspaceRoot ?? os . homedir ( ) ;
668+ debugLog ( 'Creating Auggie Client' , { model : auggieModel , apiUrl : sess . tenantURL , workspaceRoot : workspace } ) ;
667669 const client = await AuggieClass . create ( {
668670 model : auggieModel ,
669671 apiKey : sess . accessToken ,
670672 apiUrl : sess . tenantURL ,
673+ workspaceRoot : workspace ,
671674 } ) ;
672- console . log ( `New Auggie client created for model: ${ auggieModel } ` ) ;
675+ console . log ( `New Auggie client created for model: ${ auggieModel } (workspace: ${ workspace } ) ` ) ;
673676 return client ;
674677}
675678
676- async function getAuggieClient ( modelId : string ) : Promise < AuggieClient > {
679+ // Generate pool key combining model and workspace
680+ function getPoolKey ( auggieModel : string , workspaceRoot ?: string ) : string {
681+ const workspace = workspaceRoot ?? os . homedir ( ) ;
682+ return `${auggieModel } :${workspace } `;
683+ }
684+
685+ async function getAuggieClient ( modelId : string , workspaceRoot ? : string ) : Promise < AuggieClient > {
677686 const modelConfig = MODEL_MAP [ modelId ] ?? MODEL_MAP [ DEFAULT_MODEL ] ;
678687 if ( ! modelConfig ) {
679688 throw new Error ( `Unknown model: ${ modelId } and default model not configured` ) ;
680689 }
681690 const auggieModel = modelConfig . auggie ;
691+ const poolKey = getPoolKey ( auggieModel , workspaceRoot ) ;
682692 debugLog ( 'getAuggieClient' , {
683693 requestedModel : modelId ,
684694 resolvedAuggieModel : auggieModel ,
685695 usingDefault : ! MODEL_MAP [ modelId ] ,
696+ workspaceRoot : workspaceRoot ?? os . homedir ( ) ,
697+ poolKey,
686698 } ) ;
687699
688- clientPools [ auggieModel ] ??= { available : [ ] , inUse : new Set ( ) , creating : 0 } ;
700+ clientPools [ poolKey ] ??= { available : [ ] , inUse : new Set ( ) , creating : 0 } ;
689701
690- const pool = clientPools [ auggieModel ] ;
702+ const pool = clientPools [ poolKey ] ;
691703
692704 if ( pool . available . length > 0 ) {
693705 const client = pool . available . pop ( ) ;
694706 if ( client ) {
695707 pool . inUse . add ( client ) ;
696708 console . log (
697- `Reusing client for ${ auggieModel } (available: ${ String ( pool . available . length ) } , inUse: ${ String ( pool . inUse . size ) } )`
709+ `Reusing client for ${ poolKey } (available: ${ String ( pool . available . length ) } , inUse: ${ String ( pool . inUse . size ) } )`
698710 ) ;
699711 return client ;
700712 }
@@ -704,11 +716,11 @@ async function getAuggieClient(modelId: string): Promise<AuggieClient> {
704716 if ( totalClients < POOL_SIZE ) {
705717 pool . creating ++ ;
706718 try {
707- const client = await createAuggieClient ( auggieModel ) ;
719+ const client = await createAuggieClient ( auggieModel , workspaceRoot ) ;
708720 pool . creating -- ;
709721 pool . inUse . add ( client ) ;
710722 console . log (
711- `Created new client for ${ auggieModel } (available: ${ String ( pool . available . length ) } , inUse: ${ String ( pool . inUse . size ) } )`
723+ `Created new client for ${ poolKey } (available: ${ String ( pool . available . length ) } , inUse: ${ String ( pool . inUse . size ) } )`
712724 ) ;
713725 return client ;
714726 } catch ( err ) {
@@ -717,37 +729,39 @@ async function getAuggieClient(modelId: string): Promise<AuggieClient> {
717729 }
718730 }
719731
720- console . log ( `Pool at capacity for ${auggieModel } , creating temporary client `) ;
721- return await createAuggieClient ( auggieModel ) ;
732+ console . log ( `Pool at capacity for ${poolKey } , creating temporary client `) ;
733+ return await createAuggieClient ( auggieModel , workspaceRoot ) ;
722734}
723735
724- function releaseAuggieClient ( modelId : string , client : AuggieClient ) : void {
736+ function releaseAuggieClient ( modelId : string , client : AuggieClient , workspaceRoot ?: string ) : void {
725737 const modelConfig = MODEL_MAP [ modelId ] ?? MODEL_MAP [ DEFAULT_MODEL ] ;
726738 if ( ! modelConfig ) return ;
727739 const auggieModel = modelConfig . auggie ;
728- const pool = clientPools [ auggieModel ] ;
740+ const poolKey = getPoolKey ( auggieModel , workspaceRoot ) ;
741+ const pool = clientPools [ poolKey ] ;
729742 if ( ! pool ) return ;
730743
731744 if ( pool . inUse . has ( client ) ) {
732745 pool . inUse . delete ( client ) ;
733746 if ( pool . available . length < POOL_SIZE ) {
734747 pool . available . push ( client ) ;
735748 console . log (
736- `Client returned to pool for ${ auggieModel } (available: ${ String ( pool . available . length ) } , inUse: ${ String ( pool . inUse . size ) } )`
749+ `Client returned to pool for ${ poolKey } (available: ${ String ( pool . available . length ) } , inUse: ${ String ( pool . inUse . size ) } )`
737750 ) ;
738751 } else {
739752 void client . close ( ) ;
740- console . log ( `Pool full, closed client for ${ auggieModel } ` ) ;
753+ console . log ( `Pool full, closed client for ${ poolKey } ` ) ;
741754 }
742755 }
743756}
744757
745758// Discard a client without returning it to the pool (used when client has errors)
746- function discardAuggieClient ( modelId : string , client : AuggieClient , reason ? : string ) : void {
759+ function discardAuggieClient ( modelId : string , client : AuggieClient , reason ? : string , workspaceRoot ? : string ) : void {
747760 const modelConfig = MODEL_MAP [ modelId ] ?? MODEL_MAP [ DEFAULT_MODEL ] ;
748761 if ( ! modelConfig ) return ;
749762 const auggieModel = modelConfig . auggie ;
750- const pool = clientPools [ auggieModel ] ;
763+ const poolKey = getPoolKey ( auggieModel , workspaceRoot ) ;
764+ const pool = clientPools [ poolKey ] ;
751765 if ( ! pool ) return ;
752766
753767 if ( pool . inUse . has ( client ) ) {
@@ -962,6 +976,28 @@ function formatMessages(messages: ChatMessage[]): string {
962976 . join ( '\n\n' ) ;
963977}
964978
979+ // Extract workspace root from messages - OpenCode sends this in system message
980+ function extractWorkspaceFromMessages ( messages : ChatMessage [ ] ) : string | null {
981+ for ( const msg of messages ) {
982+ if ( msg . role === 'system' && msg . content ) {
983+ // Pattern 1: <supervisor>The user's workspace is opened at /path/to/workspace.</supervisor>
984+ const supervisorMatch = msg . content . match (
985+ / < s u p e r v i s o r > [ ^ < ] * ?(?: w o r k s p a c e i s o p e n e d a t | w o r k s p a c e i s ) \s + [ ` " ' ] ? ( [ ^ ` " ' < \n ] + ) [ ` " ' ] ? / i
986+ ) ;
987+ if ( supervisorMatch ?. [ 1 ] ) {
988+ return supervisorMatch [ 1 ] . trim ( ) . replace ( / \. $ / , '' ) ;
989+ }
990+
991+ // Pattern 2: Workspace: /path/to/workspace
992+ const workspaceMatch = msg . content . match ( / (?: w o r k s p a c e | w o r k i n g d i r e c t o r y | c w d ) : \s * [ ` " ' ] ? ( [ ^ \s ` " ' \n ] + ) / i) ;
993+ if ( workspaceMatch ?. [ 1 ] ) {
994+ return workspaceMatch [ 1 ] . trim ( ) ;
995+ }
996+ }
997+ }
998+ return null ;
999+ }
1000+
9651001// Estimate token counts (rough approximation: ~4 chars per token)
9661002function estimateTokens ( text : string ) : number {
9671003 return Math . ceil ( text . length / 4 ) ;
@@ -1255,12 +1291,13 @@ async function callAugmentAPIStreamingInternal(
12551291 res: ServerResponse,
12561292 requestId: string,
12571293 model: string,
1294+ workspaceRoot?: string,
12581295 abortSignal?: AbortSignal
12591296): Promise<void> {
12601297 const startTime = Date.now();
1261- console.log(` [ $ { requestId} ] 🚀 Starting streaming call to ${modelId } ( prompt : ${String ( prompt . length ) } chars ) `);
1298+ console.log(` [ $ { requestId} ] 🚀 Starting streaming call to ${modelId } ( prompt : ${String ( prompt . length ) } chars , workspace : ${ workspaceRoot ?? 'default' } ) `);
12621299
1263- const client = await getAuggieClient(modelId);
1300+ const client = await getAuggieClient(modelId, workspaceRoot );
12641301 client.onSessionUpdate(createStreamCallback(res, model, requestId));
12651302 let hasError = false;
12661303 let caughtError: Error | null = null;
@@ -1301,15 +1338,15 @@ async function callAugmentAPIStreamingInternal(
13011338 // Discard client on session errors or aborts, otherwise return to pool
13021339 if (hasError && caughtError) {
13031340 if (caughtError.message === 'Request aborted') {
1304- discardAuggieClient(modelId, client, 'request aborted/timeout');
1341+ discardAuggieClient(modelId, client, 'request aborted/timeout', workspaceRoot );
13051342 } else if (isSessionError(caughtError)) {
1306- discardAuggieClient(modelId, client, 'session/connection error');
1343+ discardAuggieClient(modelId, client, 'session/connection error', workspaceRoot );
13071344 } else {
13081345 // Other errors - still return client to pool
1309- releaseAuggieClient(modelId, client);
1346+ releaseAuggieClient(modelId, client, workspaceRoot );
13101347 }
13111348 } else {
1312- releaseAuggieClient(modelId, client);
1349+ releaseAuggieClient(modelId, client, workspaceRoot );
13131350 }
13141351 }
13151352 if (caughtError) {
@@ -1323,10 +1360,11 @@ async function callAugmentAPIStreaming(
13231360 res: ServerResponse,
13241361 requestId: string,
13251362 model: string,
1363+ workspaceRoot?: string,
13261364 abortSignal?: AbortSignal
13271365): Promise<void> {
13281366 await withRetry(
1329- () => callAugmentAPIStreamingInternal(prompt, modelId, res, requestId, model, abortSignal),
1367+ () => callAugmentAPIStreamingInternal(prompt, modelId, res, requestId, model, workspaceRoot, abortSignal),
13301368 'Augment API Streaming',
13311369 requestId
13321370 );
@@ -1335,9 +1373,10 @@ async function callAugmentAPIStreaming(
13351373async function callAugmentAPIInternal(
13361374 prompt: string,
13371375 modelId: string,
1376+ workspaceRoot?: string,
13381377 abortSignal?: AbortSignal
13391378): Promise<string> {
1340- const client = await getAuggieClient(modelId);
1379+ const client = await getAuggieClient(modelId, workspaceRoot );
13411380 let hasError = false;
13421381 let caughtError: Error | null = null;
13431382 let result = '';
@@ -1377,15 +1416,15 @@ async function callAugmentAPIInternal(
13771416 // Discard client on session errors or aborts, otherwise return to pool
13781417 if (hasError && caughtError) {
13791418 if (caughtError.message === 'Request aborted') {
1380- discardAuggieClient(modelId, client, 'request aborted/timeout');
1419+ discardAuggieClient(modelId, client, 'request aborted/timeout', workspaceRoot );
13811420 } else if (isSessionError(caughtError)) {
1382- discardAuggieClient(modelId, client, 'session/connection error');
1421+ discardAuggieClient(modelId, client, 'session/connection error', workspaceRoot );
13831422 } else {
13841423 // Other errors - still return client to pool
1385- releaseAuggieClient(modelId, client);
1424+ releaseAuggieClient(modelId, client, workspaceRoot );
13861425 }
13871426 } else {
1388- releaseAuggieClient(modelId, client);
1427+ releaseAuggieClient(modelId, client, workspaceRoot );
13891428 }
13901429 }
13911430 if (caughtError) {
@@ -1398,10 +1437,11 @@ async function callAugmentAPI(
13981437 prompt: string,
13991438 modelId: string,
14001439 requestId: string,
1440+ workspaceRoot?: string,
14011441 abortSignal?: AbortSignal
14021442): Promise<string> {
14031443 return withRetry(
1404- () => callAugmentAPIInternal(prompt, modelId, abortSignal),
1444+ () => callAugmentAPIInternal(prompt, modelId, workspaceRoot, abortSignal),
14051445 'Augment API',
14061446 requestId
14071447 );
@@ -1496,6 +1536,12 @@ async function handleChatCompletions(req: IncomingMessage, res: ServerResponse):
14961536 const stream = body.stream ?? false;
14971537 const model = body.model ?? DEFAULT_MODEL;
14981538
1539+ // Extract workspace root from messages (OpenCode sends this in system message)
1540+ const workspaceRoot = extractWorkspaceFromMessages(messages);
1541+ if (workspaceRoot) {
1542+ structuredLog('info', 'Request', ` Extracted workspace : ${workspaceRoot } `, { requestId });
1543+ }
1544+
14991545 // Track model usage
15001546 metrics.requestsByModel[model] = (metrics.requestsByModel[model] ?? 0) + 1;
15011547
@@ -1511,7 +1557,7 @@ async function handleChatCompletions(req: IncomingMessage, res: ServerResponse):
15111557 const prompt = formatMessages ( messages ) ;
15121558 structuredLog ( 'info ', 'Request ', `Processing request `, {
15131559 requestId,
1514- data: { model, stream, messageCount: messages.length },
1560+ data: { model, stream, messageCount: messages.length, workspace: workspaceRoot ?? 'default' },
15151561 });
15161562
15171563 // Check for abort before making API call
@@ -1533,7 +1579,7 @@ async function handleChatCompletions(req: IncomingMessage, res: ServerResponse):
15331579 res.flushHeaders();
15341580
15351581 try {
1536- await callAugmentAPIStreaming(prompt, model, res, requestId, model, abortController.signal);
1582+ await callAugmentAPIStreaming(prompt, model, res, requestId, model, workspaceRoot ?? undefined, abortController.signal);
15371583 res.write(createStreamChunk('', model, true));
15381584 res.write('data: [DONE]\n\n');
15391585 cleanup(true);
@@ -1547,7 +1593,7 @@ async function handleChatCompletions(req: IncomingMessage, res: ServerResponse):
15471593 }
15481594 res.end();
15491595 } else {
1550- const response = await callAugmentAPI(prompt, model, requestId, abortController.signal);
1596+ const response = await callAugmentAPI(prompt, model, requestId, workspaceRoot ?? undefined, abortController.signal);
15511597 res.writeHead(200, { 'Content-Type': 'application/json' });
15521598 res.end(JSON.stringify(createChatResponse(response, model, prompt)));
15531599 cleanup(true);
0 commit comments