@@ -127,6 +127,9 @@ const additionalContentInnerContextLimit = 8192
127127
128128const aditionalContentNameLimit = 1024
129129
130+ // temporary limit for @workspace and @file combined context length
131+ const contextMaxLength = 40_000
132+
130133const getUserPromptsDirectory = ( ) => {
131134 return path . join ( fs . getUserHomeDir ( ) , '.aws' , 'amazonq' , 'prompts' )
132135}
@@ -915,28 +918,38 @@ export class ChatController {
915918 }
916919 const workspaceFolder = contextCommands [ 0 ] . workspaceFolder
917920 const prompts = await LspClient . instance . getContextCommandPrompt ( contextCommands )
918- if ( prompts . length > 0 ) {
919- triggerPayload . additionalContents = [ ]
920- for ( const prompt of prompts ) {
921- // Todo: add mechanism for sorting/prioritization of additional context
922- if ( triggerPayload . additionalContents . length < 20 ) {
923- triggerPayload . additionalContents . push ( {
924- name : prompt . name . substring ( 0 , aditionalContentNameLimit ) ,
925- description : prompt . description . substring ( 0 , aditionalContentNameLimit ) ,
926- innerContext : prompt . content . substring ( 0 , additionalContentInnerContextLimit ) ,
927- } )
928- let relativePath = path . relative ( workspaceFolder , prompt . filePath )
929- // Handle user prompts outside the workspace
930- if ( prompt . filePath . startsWith ( getUserPromptsDirectory ( ) ) ) {
931- relativePath = path . basename ( prompt . filePath )
932- }
933- relativePaths . push ( relativePath )
934- }
921+ if ( prompts . length === 0 ) {
922+ return [ ]
923+ }
924+
925+ let currentContextLength = 0
926+ triggerPayload . additionalContents = [ ]
927+ for ( const prompt of prompts . slice ( 0 , 20 ) ) {
928+ // Todo: add mechanism for sorting/prioritization of additional context
929+ const entry = {
930+ name : prompt . name . substring ( 0 , aditionalContentNameLimit ) ,
931+ description : prompt . description . substring ( 0 , aditionalContentNameLimit ) ,
932+ innerContext : prompt . content . substring ( 0 , additionalContentInnerContextLimit ) ,
935933 }
936- getLogger ( ) . info (
937- `Retrieved chunks of additional context count: ${ triggerPayload . additionalContents . length } `
938- )
934+ // make sure the relevantDocument + additionalContext
935+ // combined does not exceed 40k characters before generating the request payload.
936+ // Do truncation and make sure triggerPayload.documentReferences is up-to-date after truncation
937+ // TODO: Use a context length indicator
938+ if ( currentContextLength + entry . innerContext . length > contextMaxLength ) {
939+ getLogger ( ) . warn ( `Selected context exceeds context size limit: ${ entry . description } ` )
940+ break
941+ }
942+ triggerPayload . additionalContents . push ( entry )
943+ currentContextLength += entry . innerContext . length
944+ let relativePath = path . relative ( workspaceFolder , prompt . filePath )
945+ // Handle user prompts outside the workspace
946+ if ( prompt . filePath . startsWith ( getUserPromptsDirectory ( ) ) ) {
947+ relativePath = path . basename ( prompt . filePath )
948+ }
949+ relativePaths . push ( relativePath )
939950 }
951+ getLogger ( ) . info ( `Retrieved chunks of additional context count: ${ triggerPayload . additionalContents . length } ` )
952+
940953 return relativePaths
941954 }
942955
@@ -973,17 +986,37 @@ export class ChatController {
973986 return
974987 }
975988
976- const relativePaths = await this . resolveContextCommandPayload ( triggerPayload )
977- triggerPayload . useRelevantDocuments = false
989+ const relativePathsOfContextCommandFiles = await this . resolveContextCommandPayload ( triggerPayload )
990+ triggerPayload . useRelevantDocuments =
991+ triggerPayload . context ?. some (
992+ ( context ) => typeof context !== 'string' && context . command === '@workspace'
993+ ) || false
978994 triggerPayload . documentReferences = [ ]
979- triggerPayload . useRelevantDocuments = triggerPayload . context ?. some (
980- ( context ) => typeof context !== 'string' && context . command === '@workspace'
981- )
982995 if ( triggerPayload . useRelevantDocuments && triggerPayload . message ) {
983996 triggerPayload . message = triggerPayload . message . replace ( / w o r k s p a c e / , '' )
984997 if ( CodeWhispererSettings . instance . isLocalIndexEnabled ( ) ) {
985998 const start = performance . now ( )
986- triggerPayload . relevantTextDocuments = await LspController . instance . query ( triggerPayload . message )
999+ let remainingContextLength = contextMaxLength
1000+ triggerPayload . additionalContents ?. forEach ( ( i ) => {
1001+ if ( i . innerContext ) {
1002+ remainingContextLength -= i . innerContext . length
1003+ }
1004+ } )
1005+ triggerPayload . relevantTextDocuments = [ ]
1006+ const relevantTextDocuments = await LspController . instance . query ( triggerPayload . message )
1007+ for ( const relevantDocument of relevantTextDocuments ) {
1008+ if ( relevantDocument . text !== undefined && relevantDocument . text . length > 0 ) {
1009+ if ( remainingContextLength > relevantDocument . text . length ) {
1010+ triggerPayload . relevantTextDocuments . push ( relevantDocument )
1011+ remainingContextLength -= relevantDocument . text . length
1012+ } else {
1013+ getLogger ( ) . warn (
1014+ `Retrieved context exceeds context size limit: ${ relevantDocument . relativeFilePath } `
1015+ )
1016+ break
1017+ }
1018+ }
1019+ }
9871020
9881021 for ( const doc of triggerPayload . relevantTextDocuments ) {
9891022 getLogger ( ) . info (
@@ -996,11 +1029,8 @@ export class ChatController {
9961029 return
9971030 }
9981031 }
999- triggerPayload . documentReferences = this . mergeRelevantTextDocuments ( triggerPayload . relevantTextDocuments || [ ] )
10001032
1001- // TODO: make sure the user input + current focused document + relevantDocument + additionalContext
1002- // combined does not exceed 100k characters before generating the request payload.
1003- // Do truncation and make sure triggerPayload.documentReferences is up-to-date after truncation
1033+ triggerPayload . documentReferences = this . mergeRelevantTextDocuments ( triggerPayload . relevantTextDocuments || [ ] )
10041034
10051035 const request = triggerPayloadToChatRequest ( triggerPayload )
10061036 const session = this . sessionStorage . getSession ( tabID )
@@ -1011,7 +1041,7 @@ export class ChatController {
10111041 const relativePathsOfMergedRelevantDocuments = triggerPayload . documentReferences . map (
10121042 ( doc ) => doc . relativeFilePath
10131043 )
1014- for ( const relativePath of relativePaths ) {
1044+ for ( const relativePath of relativePathsOfContextCommandFiles ) {
10151045 if ( ! relativePathsOfMergedRelevantDocuments . includes ( relativePath ) ) {
10161046 triggerPayload . documentReferences . push ( {
10171047 relativeFilePath : relativePath ,
0 commit comments