Skip to content

Commit 0a9ee21

Browse files
committed
Merge branch 'feature/hybridChat' into feature/agentic-chat-beta
2 parents 085f816 + 8b7106b commit 0a9ee21

File tree

17 files changed

+127
-46
lines changed

17 files changed

+127
-46
lines changed

packages/amazonq/src/app/chat/activation.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export async function activate(context: ExtensionContext) {
1818
void amazonq.LspController.instance.trySetupLsp(context, {
1919
startUrl: AuthUtil.instance.startUrl,
2020
maxIndexSize: CodeWhispererSettings.instance.getMaxIndexSize(),
21-
isVectorIndexEnabled: CodeWhispererSettings.instance.isLocalIndexEnabled(),
21+
isVectorIndexEnabled: false,
2222
})
2323
}, 5000)
2424

@@ -30,14 +30,7 @@ export async function activate(context: ExtensionContext) {
3030
amazonq.listCodeWhispererCommandsWalkthrough.register(),
3131
amazonq.focusAmazonQPanel.register(),
3232
amazonq.focusAmazonQPanelKeybinding.register(),
33-
amazonq.tryChatCodeLensCommand.register(),
34-
vscode.workspace.onDidChangeConfiguration(async (configurationChangeEvent) => {
35-
if (configurationChangeEvent.affectsConfiguration('amazonQ.workspaceIndex')) {
36-
if (CodeWhispererSettings.instance.isLocalIndexEnabled()) {
37-
void setupLsp()
38-
}
39-
}
40-
})
33+
amazonq.tryChatCodeLensCommand.register()
4134
)
4235

4336
Commands.register('aws.amazonq.learnMore', () => {

packages/amazonq/src/lsp/auth.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,29 @@ export const notificationTypes = {
6666
* Facade over our VSCode Auth that does crud operations on the language server auth
6767
*/
6868
export class AmazonQLspAuth {
69-
constructor(private readonly client: LanguageClient) {}
69+
#logErrorIfChanged = onceChanged((s) => getLogger('amazonqLsp').error(s))
70+
constructor(
71+
private readonly client: LanguageClient,
72+
private readonly authUtil: AuthUtil = AuthUtil.instance
73+
) {}
7074

7175
/**
7276
* @param force bypass memoization, and forcefully update the bearer token
7377
*/
7478
async refreshConnection(force: boolean = false) {
75-
const activeConnection = AuthUtil.instance.auth.activeConnection
76-
if (activeConnection?.type === 'sso') {
79+
const activeConnection = this.authUtil.auth.activeConnection
80+
if (activeConnection?.state === 'valid' && activeConnection?.type === 'sso') {
7781
// send the token to the language server
78-
const token = await AuthUtil.instance.getBearerToken()
82+
const token = await this.authUtil.getBearerToken()
7983
await (force ? this._updateBearerToken(token) : this.updateBearerToken(token))
8084
}
8185
}
8286

87+
async logRefreshError(e: unknown) {
88+
const err = e as Error
89+
this.#logErrorIfChanged(`Unable to update bearer token: ${err.name}:${err.message}`)
90+
}
91+
8392
public updateBearerToken = onceChanged(this._updateBearerToken.bind(this))
8493
private async _updateBearerToken(token: string) {
8594
const request = await this.createUpdateCredentialsRequest({
@@ -93,10 +102,7 @@ export class AmazonQLspAuth {
93102

94103
public startTokenRefreshInterval(pollingTime: number = oneMinute / 2) {
95104
const interval = setInterval(async () => {
96-
await this.refreshConnection().catch((e) => {
97-
getLogger('amazonqLsp').error('Unable to update bearer token: %s', (e as Error).message)
98-
clearInterval(interval)
99-
})
105+
await this.refreshConnection().catch((e) => this.logRefreshError(e))
100106
}, pollingTime)
101107
return interval
102108
}

packages/amazonq/src/lsp/chat/commands.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import { Commands, globals } from 'aws-core-vscode/shared'
77
import { window } from 'vscode'
88
import { AmazonQChatViewProvider } from './webviewProvider'
9+
import { CodeScanIssue } from 'aws-core-vscode/codewhisperer'
10+
import { EditorContextExtractor } from 'aws-core-vscode/codewhispererChat'
11+
import { DefaultAmazonQAppInitContext } from 'aws-core-vscode/amazonq'
912

1013
/**
1114
* TODO: Re-enable these once we can figure out which path they're going to live in
@@ -17,6 +20,52 @@ export function registerCommands(provider: AmazonQChatViewProvider) {
1720
registerGenericCommand('aws.amazonq.refactorCode', 'Refactor', provider),
1821
registerGenericCommand('aws.amazonq.fixCode', 'Fix', provider),
1922
registerGenericCommand('aws.amazonq.optimizeCode', 'Optimize', provider),
23+
Commands.register('aws.amazonq.generateUnitTests', async () => {
24+
DefaultAmazonQAppInitContext.instance.getAppsToWebViewMessagePublisher().publish({
25+
sender: 'testChat',
26+
command: 'test',
27+
type: 'chatMessage',
28+
})
29+
}),
30+
Commands.register('aws.amazonq.explainIssue', async (issue: CodeScanIssue) => {
31+
void focusAmazonQPanel().then(async () => {
32+
const editorContextExtractor = new EditorContextExtractor()
33+
const extractedContext = await editorContextExtractor.extractContextForTrigger('ContextMenu')
34+
const selectedCode =
35+
extractedContext?.activeFileContext?.fileText
36+
?.split('\n')
37+
.slice(issue.startLine, issue.endLine)
38+
.join('\n') ?? ''
39+
40+
// The message that gets sent to the UI
41+
const uiMessage = [
42+
'Explain the ',
43+
issue.title,
44+
' issue in the following code:',
45+
'\n```\n',
46+
selectedCode,
47+
'\n```',
48+
].join('')
49+
50+
// The message that gets sent to the backend
51+
const contextMessage = `Explain the issue "${issue.title}" (${JSON.stringify(
52+
issue
53+
)}) and generate code demonstrating the fix`
54+
55+
void provider.webview?.postMessage({
56+
command: 'sendToPrompt',
57+
params: {
58+
selection: '',
59+
triggerType: 'contextMenu',
60+
prompt: {
61+
prompt: uiMessage, // what gets sent to the user
62+
escapedPrompt: contextMessage, // what gets sent to the backend
63+
},
64+
autoSubmit: true,
65+
},
66+
})
67+
})
68+
}),
2069
Commands.register('aws.amazonq.sendToPrompt', (data) => {
2170
const triggerType = getCommandTriggerType(data)
2271
const selection = getSelectedText()

packages/amazonq/src/lsp/chat/messages.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,14 @@ import * as vscode from 'vscode'
5757
import { Disposable, LanguageClient, Position, TextDocumentIdentifier } from 'vscode-languageclient'
5858
import * as jose from 'jose'
5959
import { AmazonQChatViewProvider } from './webviewProvider'
60-
import { AuthUtil } from 'aws-core-vscode/codewhisperer'
60+
import { AuthUtil, ReferenceLogViewProvider } from 'aws-core-vscode/codewhisperer'
6161
import { amazonQDiffScheme, AmazonQPromptSettings, messages, openUrl } from 'aws-core-vscode/shared'
6262
import {
6363
DefaultAmazonQAppInitContext,
6464
messageDispatcher,
6565
EditorContentController,
6666
ViewDiffMessage,
67+
referenceLogText,
6768
} from 'aws-core-vscode/amazonq'
6869
import { telemetry, TelemetryBase } from 'aws-core-vscode/telemetry'
6970
import { isValidResponseError } from './error'
@@ -537,20 +538,25 @@ async function handlePartialResult<T extends ChatResult>(
537538
* Decodes the final chat responses from the language server before sending it to mynah UI.
538539
* Once this is called the answer response is finished
539540
*/
540-
async function handleCompleteResult<T>(
541+
async function handleCompleteResult<T extends ChatResult>(
541542
result: string | T,
542543
encryptionKey: Buffer | undefined,
543544
provider: AmazonQChatViewProvider,
544545
tabId: string,
545546
disposable: Disposable
546547
) {
547548
const decryptedMessage =
548-
typeof result === 'string' && encryptionKey ? await decodeRequest(result, encryptionKey) : result
549+
typeof result === 'string' && encryptionKey ? await decodeRequest<T>(result, encryptionKey) : (result as T)
549550
void provider.webview?.postMessage({
550551
command: chatRequestType.method,
551552
params: decryptedMessage,
552553
tabId: tabId,
553554
})
555+
556+
// only add the reference log once the request is complete, otherwise we will get duplicate log items
557+
for (const ref of decryptedMessage.codeReference ?? []) {
558+
ReferenceLogViewProvider.instance.addReferenceLog(referenceLogText(ref))
559+
}
554560
disposable.dispose()
555561
}
556562

packages/amazonq/src/lsp/chat/webviewProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ export class AmazonQChatViewProvider implements WebviewViewProvider {
139139
const vscodeApi = acquireVsCodeApi()
140140
const hybridChatConnector = new HybridChatAdapter(${(await AuthUtil.instance.getChatAuthState()).amazonQ === 'connected'},${featureConfigData},${welcomeCount},${disclaimerAcknowledged},${regionProfileString},${disabledCommands},${isSMUS},${isSM},vscodeApi.postMessage)
141141
const commands = [hybridChatConnector.initialQuickActions[0]]
142-
qChat = amazonQChat.createChat(vscodeApi, {disclaimerAcknowledged: ${disclaimerAcknowledged}, pairProgrammingAcknowledged: ${pairProgrammingAcknowledged}, quickActionCommands: commands}, hybridChatConnector, ${JSON.stringify(featureConfigData)});
142+
qChat = amazonQChat.createChat(vscodeApi, {disclaimerAcknowledged: ${disclaimerAcknowledged}, pairProgrammingAcknowledged: ${pairProgrammingAcknowledged}, agenticMode: true, quickActionCommands: commands}, hybridChatConnector, ${JSON.stringify(featureConfigData)});
143143
}
144144
window.addEventListener('message', (event) => {
145145
/**

packages/amazonq/src/lsp/client.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import {
2323
import { AuthUtil, CodeWhispererSettings, getSelectedCustomization } from 'aws-core-vscode/codewhisperer'
2424
import {
2525
Settings,
26-
oidcClientName,
2726
createServerOptions,
2827
globals,
2928
Experiments,
@@ -95,14 +94,14 @@ export async function startLanguageServer(
9594
name: env.appName,
9695
version: version,
9796
extension: {
98-
name: oidcClientName(),
97+
name: 'AmazonQ-For-VSCode',
9998
version: '0.0.1',
10099
},
101100
clientId: crypto.randomUUID(),
102101
},
103102
awsClientCapabilities: {
104103
q: {
105-
developerProfiles: false,
104+
developerProfiles: true,
106105
},
107106
window: {
108107
notifications: true,
@@ -282,8 +281,7 @@ function getConfigSection(section: ConfigSection) {
282281
customization: undefinedIfEmpty(getSelectedCustomization().arn),
283282
optOutTelemetry: getOptOutPreference() === 'OPTOUT',
284283
projectContext: {
285-
// TODO: we might need another setting to control the actual indexing
286-
enableLocalIndexing: true,
284+
enableLocalIndexing: CodeWhispererSettings.instance.isLocalIndexEnabled(),
287285
enableGpuAcceleration: CodeWhispererSettings.instance.isLocalIndexGPUEnabled(),
288286
indexWorkerThreads: CodeWhispererSettings.instance.getIndexWorkerThreads(),
289287
localIndexing: {

packages/core/src/amazonq/commons/model.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6+
import { LicenseUtil } from '../../codewhisperer/util/licenseUtil'
7+
import { CodeReference } from '../../codewhispererChat/view/connector/connector'
8+
69
// Currently importing ChatItemType in Mynah UI from the vscode side causes an error
710
// TODO remove this once the import stops failing
811
export type ChatItemType =
@@ -13,3 +16,10 @@ export type ChatItemType =
1316
| 'answer-stream'
1417
| 'answer-part'
1518
| 'code-result'
19+
20+
export const referenceLogText = (reference: CodeReference) =>
21+
`[${new Date().toLocaleString()}] Accepted recommendation from Amazon Q. Code provided with reference under <a href="${LicenseUtil.getLicenseHtml(
22+
reference.licenseName
23+
)}" target="_blank">${reference.licenseName}</a> license from repository <a href="${
24+
reference.url
25+
}" target="_blank">${reference.repository}</a>.<br><br>`

packages/core/src/amazonq/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export {
3535
computeDiff,
3636
} from './commons/diff'
3737
export { AuthFollowUpType, AuthMessageDataMap } from './auth/model'
38-
export { ChatItemType } from './commons/model'
38+
export { ChatItemType, referenceLogText } from './commons/model'
3939
export { ExtensionMessage } from '../amazonq/webview/ui/commands'
4040
export { CodeReference } from '../codewhispererChat/view/connector/connector'
4141
export { extractAuthFollowUp } from './util/authUtils'

packages/core/src/amazonq/webview/ui/quickActions/handler.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export class QuickActionHandler {
107107
}
108108
}
109109

110-
private handleScanCommand(tabID: string, eventId: string | undefined) {
110+
private handleScanCommand(tabID: string | undefined, eventId: string | undefined) {
111111
if (!this.isScanEnabled || !this.mynahUI) {
112112
return
113113
}
@@ -126,6 +126,14 @@ export class QuickActionHandler {
126126
return
127127
}
128128

129+
/**
130+
* status bar -> "full project scan is now /review" doesn't have a tab ID
131+
* since it's called via a command so we need to manually create one
132+
*/
133+
if (!tabID) {
134+
tabID = this.mynahUI.updateStore('', {})
135+
}
136+
129137
// if there is no scan tab, open a new one
130138
const affectedTabId: string | undefined = this.addTab(tabID)
131139

@@ -155,7 +163,7 @@ export class QuickActionHandler {
155163
}
156164
}
157165

158-
private handleTestCommand(chatPrompt: ChatPrompt, tabID: string, eventId: string | undefined) {
166+
private handleTestCommand(chatPrompt: ChatPrompt, tabID: string | undefined, eventId: string | undefined) {
159167
if (!this.isTestEnabled || !this.mynahUI) {
160168
return
161169
}
@@ -169,6 +177,15 @@ export class QuickActionHandler {
169177
return
170178
}
171179

180+
/**
181+
* right click -> generate test has no tab id
182+
* we have to manually create one if a testgen tab
183+
* wasn't previously created
184+
*/
185+
if (!tabID) {
186+
tabID = this.mynahUI.updateStore('', {})
187+
}
188+
172189
// if there is no test tab, open a new one
173190
const affectedTabId: string | undefined = this.addTab(tabID)
174191

packages/core/src/amazonqDoc/session/session.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { TelemetryHelper } from '../../amazonq/util/telemetryHelper'
1515
import { ConversationNotStartedState } from '../../amazonqFeatureDev/session/sessionState'
1616
import { logWithConversationId } from '../../amazonqFeatureDev/userFacingText'
1717
import { ConversationIdNotFoundError, IllegalStateError } from '../../amazonqFeatureDev/errors'
18-
import { referenceLogText } from '../../amazonqFeatureDev/constants'
18+
import { referenceLogText } from '../../amazonq/commons/model'
1919
import {
2020
DocInteractionType,
2121
DocV2AcceptanceEvent,

0 commit comments

Comments
 (0)