Skip to content

Commit 1332eda

Browse files
committed
merge: resolve import conflicts
2 parents 2cddcae + 8680e75 commit 1332eda

34 files changed

+1293
-664
lines changed

package-lock.json

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"skippedTestReport": "ts-node ./scripts/skippedTestReport.ts ./packages/amazonq/test/e2e/"
4242
},
4343
"devDependencies": {
44-
"@aws-toolkits/telemetry": "^1.0.296",
44+
"@aws-toolkits/telemetry": "^1.0.301",
4545
"@playwright/browser-chromium": "^1.43.1",
4646
"@stylistic/eslint-plugin": "^2.11.0",
4747
"@types/he": "^1.2.3",
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "Amazon Q chat: Add support for `.md` file rules in workspace-level `.amazonq/rules` directory"
4+
}

packages/core/package.nls.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
"AWS.stepFunctions.executeStateMachine.error.failedToStart": "There was an error starting execution for '{0}', check AWS Toolkit logs for more information.",
3535
"AWS.stepFunctions.asl.format.enable.desc": "Enables the default formatter used with Amazon States Language files",
3636
"AWS.stepFunctions.asl.maxItemsComputed.desc": "The maximum number of outline symbols and folding regions computed (limited for performance reasons).",
37+
"AWS.stepFunctions.workflowStudio.actions.progressMessage": "Opening asl file in Workflow Studio",
38+
"AWS.stepFunctions.workflowStudio.actions.saveSuccessMessage": "{0} has been saved",
39+
"AWS.stepFunctions.workflowStudio.actions.InvalidJSONContent": "The Workflow Studio editor was not opened because the JSON in the file is invalid. To access Workflow Studio, please fix the JSON and manually reopen the integration.",
40+
"AWS.stepFunctions.workflowStudio.actions.InvalidYAMLContent": "The Workflow Studio editor was not opened because the YAML in the file is invalid. To access Workflow Studio, please fix the YAML and manually reopen the integration.",
41+
"AWS.stepFunctions.workflowStudio.actions.webviewFetchFailed": "Failed to load Workflow Studio editor. Please check your network connection and try again.",
3742
"AWS.configuration.description.awssam.debug.api": "API Gateway configuration",
3843
"AWS.configuration.description.awssam.debug.api.clientCertId": "The API Gateway client certificate ID",
3944
"AWS.configuration.description.awssam.debug.api.headers": "Additional HTTP headers",
@@ -177,7 +182,6 @@
177182
"AWS.command.viewSchemaItem": "View Schema",
178183
"AWS.command.searchSchema": "Search Schemas",
179184
"AWS.command.executeStateMachine": "Start Execution...",
180-
"AWS.command.renderStateMachineGraph": "Render graph",
181185
"AWS.command.copyArn": "Copy ARN",
182186
"AWS.command.copyName": "Copy Name",
183187
"AWS.command.openAwsConsole": "Go to AWS management console",
@@ -219,7 +223,7 @@
219223
"AWS.command.s3.uploadFileToParent": "Upload to Parent...",
220224
"AWS.command.stepFunctions.createStateMachineFromTemplate": "Create a new Step Functions state machine",
221225
"AWS.command.stepFunctions.publishStateMachine": "Publish state machine to Step Functions",
222-
"AWS.command.stepFunctions.previewStateMachine": "Render state machine graph",
226+
"AWS.command.stepFunctions.openWithWorkflowStudio": "Open with Workflow Studio",
223227
"AWS.command.cdk.previewStateMachine": "Render state machine graph from CDK application",
224228
"AWS.command.copyLogResource": "Copy Log Stream or Group",
225229
"AWS.command.saveCurrentLogDataContent": "Save Log to File",

packages/core/src/amazonq/webview/ui/texts/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ export const helpMessage = `I'm Amazon Q, a generative AI assistant. Learn more
4444
\n\n- Answer questions about AWS
4545
\n\n- Answer questions about general programming concepts
4646
\n\n- Answer questions about your workspace with @workspace
47+
\n\n- Answer questions about your code with @Files and @Folders
48+
\n\n- Create and use saved prompts with @Prompts
4749
\n\n- Explain what a line of code or code function does
4850
\n\n- Write unit tests and code
4951
\n\n- Debug and fix code

packages/core/src/awsexplorer/activation.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -190,15 +190,6 @@ async function registerAwsExplorerCommands(
190190
'aws.executeStateMachine',
191191
async (node: StateMachineNode) => await executeStateMachine(context, node)
192192
),
193-
Commands.register(
194-
'aws.renderStateMachineGraph',
195-
async (node: StateMachineNode) =>
196-
await downloadStateMachineDefinition({
197-
stateMachineNode: node,
198-
outputChannel: toolkitOutputChannel,
199-
isPreviewAndRender: true,
200-
})
201-
),
202193
Commands.register('aws.copyArn', async (node: AWSResourceNode | TreeNode) => {
203194
const sourceNode = getSourceNode<AWSResourceNode>(node)
204195
await copyTextCommand(sourceNode, 'ARN')

packages/core/src/codewhispererChat/controllers/chat/controller.ts

Lines changed: 75 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ import { DefaultAmazonQAppInitContext } from '../../../amazonq/apps/initContext'
6666
import globals from '../../../shared/extensionGlobals'
6767
import { MynahIconsType, MynahUIDataModel, QuickActionCommand } from '@aws/mynah-ui'
6868
import { LspClient } from '../../../amazonq/lsp/lspClient'
69-
import { ContextCommandItem, ContextCommandItemType } from '../../../amazonq/lsp/types'
69+
import { AdditionalContextPrompt, ContextCommandItem, ContextCommandItemType } from '../../../amazonq/lsp/types'
7070
import { workspaceCommand } from '../../../amazonq/webview/ui/tabs/constants'
7171
import fs from '../../../shared/fs/fs'
7272
import { FeatureConfigProvider, Features } from '../../../shared/featureConfig'
@@ -588,8 +588,9 @@ export class ChatController {
588588
return
589589
}
590590

591-
// TODO: Fix for multiple workspace setup
592-
const projectRoot = session.relativePathToWorkspaceRoot.get(message.filePath)
591+
// Check if clicked file is in a different workspace root
592+
const projectRoot =
593+
session.relativePathToWorkspaceRoot.get(message.filePath) || workspace.workspaceFolders?.[0]?.uri.fsPath
593594
if (!projectRoot) {
594595
return
595596
}
@@ -877,6 +878,34 @@ export class ChatController {
877878
this.messenger.sendStaticTextResponse(responseType, triggerID, tabID)
878879
}
879880

881+
/**
882+
* @returns A Uri array of prompt files in each workspace root's .amazonq/rules directory
883+
*/
884+
private async collectWorkspaceRules(): Promise<vscode.Uri[]> {
885+
const rulesFiles: vscode.Uri[] = []
886+
887+
if (!vscode.workspace.workspaceFolders) {
888+
return rulesFiles
889+
}
890+
891+
for (const folder of vscode.workspace.workspaceFolders) {
892+
const rulesPath = vscode.Uri.joinPath(folder.uri, '.amazonq', 'rules')
893+
const folderExists = await fs.exists(rulesPath)
894+
895+
if (folderExists) {
896+
const entries = await fs.readdir(rulesPath)
897+
898+
for (const [name, type] of entries) {
899+
if (type === vscode.FileType.File && name.endsWith(promptFileExtension)) {
900+
rulesFiles.push(vscode.Uri.joinPath(rulesPath, name))
901+
}
902+
}
903+
}
904+
}
905+
906+
return rulesFiles
907+
}
908+
880909
private async resolveContextCommandPayload(
881910
triggerPayload: TriggerPayload,
882911
session: ChatSession
@@ -885,14 +914,13 @@ export class ChatController {
885914
const relativePaths: string[] = []
886915

887916
// Check for workspace rules to add to context
888-
const workspaceRules = await vscode.workspace.findFiles(`.amazonq/rules/*${promptFileExtension}`)
917+
const workspaceRules = await this.collectWorkspaceRules()
889918
if (workspaceRules.length > 0) {
890919
contextCommands.push(
891920
...workspaceRules.map((rule) => {
892921
const workspaceFolderPath = vscode.workspace.getWorkspaceFolder(rule)?.uri?.path || ''
893922
return {
894923
workspaceFolder: workspaceFolderPath,
895-
// todo: add 'prompt' type to LSP model
896924
type: 'file' as ContextCommandItemType,
897925
relativePath: path.relative(workspaceFolderPath, rule.path),
898926
}
@@ -904,7 +932,6 @@ export class ChatController {
904932
// Add context commands added by user to context
905933
if (triggerPayload.context !== undefined && triggerPayload.context.length > 0) {
906934
for (const context of triggerPayload.context) {
907-
// todo: add handling of 'prompt' type (dependent on LSP changes)
908935
if (typeof context !== 'string' && context.route && context.route.length === 2) {
909936
contextCommands.push({
910937
workspaceFolder: context.route[0] || '',
@@ -930,52 +957,59 @@ export class ChatController {
930957
)
931958
session.relativePathToWorkspaceRoot.set(relativePath, contextCommand.workspaceFolder)
932959
}
933-
const prompts = await LspClient.instance.getContextCommandPrompt(contextCommands)
934-
if (prompts.length === 0) {
935-
return []
960+
let prompts: AdditionalContextPrompt[] = []
961+
try {
962+
prompts = await LspClient.instance.getContextCommandPrompt(contextCommands)
963+
} catch (e) {
964+
// todo: handle @workspace used before indexing is ready
965+
getLogger().verbose(`Could not get context command prompts: ${e}`)
936966
}
937967

938968
let currentContextLength = 0
939969
triggerPayload.additionalContents = []
940-
triggerPayload.additionalContextLengths = this.telemetryHelper.getContextLengths(prompts)
941-
triggerPayload.truncatedAdditionalContextLengths = {
970+
const emptyLengths = {
942971
fileContextLength: 0,
943972
promptContextLength: 0,
944973
ruleContextLength: 0,
945974
}
946-
for (const prompt of prompts.slice(0, 20)) {
947-
// Todo: add mechanism for sorting/prioritization of additional context
948-
const entry = {
949-
name: prompt.name.substring(0, aditionalContentNameLimit),
950-
description: prompt.description.substring(0, aditionalContentNameLimit),
951-
innerContext: prompt.content.substring(0, additionalContentInnerContextLimit),
952-
}
953-
// make sure the relevantDocument + additionalContext
954-
// combined does not exceed 40k characters before generating the request payload.
955-
// Do truncation and make sure triggerPayload.documentReferences is up-to-date after truncation
956-
// TODO: Use a context length indicator
957-
if (currentContextLength + entry.innerContext.length > contextMaxLength) {
958-
getLogger().warn(`Selected context exceeds context size limit: ${entry.description} `)
959-
break
960-
}
975+
triggerPayload.additionalContextLengths = emptyLengths
976+
triggerPayload.truncatedAdditionalContextLengths = emptyLengths
977+
978+
if (Array.isArray(prompts) && prompts.length > 0) {
979+
triggerPayload.additionalContextLengths = this.telemetryHelper.getContextLengths(prompts)
980+
for (const prompt of prompts.slice(0, 20)) {
981+
const entry = {
982+
name: prompt.name.substring(0, aditionalContentNameLimit),
983+
description: prompt.description.substring(0, aditionalContentNameLimit),
984+
innerContext: prompt.content.substring(0, additionalContentInnerContextLimit),
985+
}
986+
// make sure the relevantDocument + additionalContext
987+
// combined does not exceed 40k characters before generating the request payload.
988+
// Do truncation and make sure triggerPayload.documentReferences is up-to-date after truncation
989+
// TODO: Use a context length indicator
990+
if (currentContextLength + entry.innerContext.length > contextMaxLength) {
991+
getLogger().warn(`Selected context exceeds context size limit: ${entry.description} `)
992+
break
993+
}
961994

962-
const contextType = this.telemetryHelper.getContextType(prompt)
963-
if (contextType === 'rule') {
964-
triggerPayload.truncatedAdditionalContextLengths.ruleContextLength += entry.innerContext.length
965-
} else if (contextType === 'prompt') {
966-
triggerPayload.truncatedAdditionalContextLengths.promptContextLength += entry.innerContext.length
967-
} else if (contextType === 'file') {
968-
triggerPayload.truncatedAdditionalContextLengths.fileContextLength += entry.innerContext.length
969-
}
995+
const contextType = this.telemetryHelper.getContextType(prompt)
996+
if (contextType === 'rule') {
997+
triggerPayload.truncatedAdditionalContextLengths.ruleContextLength += entry.innerContext.length
998+
} else if (contextType === 'prompt') {
999+
triggerPayload.truncatedAdditionalContextLengths.promptContextLength += entry.innerContext.length
1000+
} else if (contextType === 'file') {
1001+
triggerPayload.truncatedAdditionalContextLengths.fileContextLength += entry.innerContext.length
1002+
}
9701003

971-
triggerPayload.additionalContents.push(entry)
972-
currentContextLength += entry.innerContext.length
973-
let relativePath = path.relative(workspaceFolder, prompt.filePath)
974-
// Handle user prompts outside the workspace
975-
if (prompt.filePath.startsWith(getUserPromptsDirectory())) {
976-
relativePath = path.basename(prompt.filePath)
1004+
triggerPayload.additionalContents.push(entry)
1005+
currentContextLength += entry.innerContext.length
1006+
let relativePath = path.relative(workspaceFolder, prompt.filePath)
1007+
// Handle user prompts outside the workspace
1008+
if (prompt.filePath.startsWith(getUserPromptsDirectory())) {
1009+
relativePath = path.basename(prompt.filePath)
1010+
}
1011+
relativePaths.push(relativePath)
9771012
}
978-
relativePaths.push(relativePath)
9791013
}
9801014
getLogger().info(`Retrieved chunks of additional context count: ${triggerPayload.additionalContents.length} `)
9811015

packages/core/src/codewhispererChat/controllers/chat/messenger/messenger.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,24 @@ export class Messenger {
136136
)
137137
}
138138
this.telemetryHelper.setResponseStreamStartTime(tabID)
139+
140+
let cwsprChatHasProjectContext = false
139141
if (
140142
triggerPayload.relevantTextDocuments &&
141143
triggerPayload.relevantTextDocuments.length > 0 &&
142144
triggerPayload.useRelevantDocuments === true
143145
) {
144-
this.telemetryHelper.setResponseFromProjectContext(messageID)
146+
cwsprChatHasProjectContext = true
145147
}
148+
const additionalCounts = this.telemetryHelper.getAdditionalContextCounts(triggerPayload)
149+
150+
this.telemetryHelper.setResponseFromAdditionalContext(messageID, {
151+
cwsprChatHasProjectContext,
152+
cwsprChatRuleContextCount: triggerPayload.workspaceRulesCount,
153+
cwsprChatFileContextCount: additionalCounts.fileContextCount,
154+
cwsprChatFolderContextCount: additionalCounts.folderContextCount,
155+
cwsprChatPromptContextCount: additionalCounts.promptContextCount,
156+
})
146157

147158
const eventCounts = new Map<string, number>()
148159
waitUntil(

packages/core/src/codewhispererChat/controllers/chat/model.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,14 @@ export type AdditionalContextLengths = {
205205
ruleContextLength: number
206206
}
207207

208+
export type AdditionalContextInfo = {
209+
cwsprChatFileContextCount?: number
210+
cwsprChatFolderContextCount?: number
211+
cwsprChatPromptContextCount?: number
212+
cwsprChatRuleContextCount?: number
213+
cwsprChatHasProjectContext?: boolean
214+
}
215+
208216
// TODO move this to API definition (or just use this across the codebase)
209217
export type RelevantTextDocumentAddition = RelevantTextDocument & { startLine: number; endLine: number }
210218

0 commit comments

Comments
 (0)