Skip to content

Commit dda8a6a

Browse files
committed
Merge remote-tracking branch 'upstream/feature/vector-custom' into feature/vector
2 parents 6748658 + 164a426 commit dda8a6a

25 files changed

+905
-35
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "SAM CLI 1.85-1.86 fails on Windows"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "CodeWhisperer improves auto-suggestions for java python typescript and csharp"
4+
}

docs/api.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# AWS Toolkit API
2+
3+
Details about any publicly accessible functionalities exposed through [extension commands](https://code.visualstudio.com/api/references/vscode-api#commands) or [exported APIs](https://code.visualstudio.com/api/references/vscode-api#extensions).
4+
5+
## Pseudo (Internal-only) API
6+
7+
### Commands
8+
9+
#### `aws.codeWhisperer.connect`
10+
11+
**Signature**: _async (startUrl?: string, region?: string) => Promise<void>_
12+
13+
Shortcut command to directly connect to Identity Center or prompt start URL entry, as well as set a customization for CodeWhisperer requests. Customization is not yet supported.
14+
15+
This command expects two arguments: startUrl and region (both strings).
16+
If these arguments are provided, they will be used. Otherwise, the commands prompts for them interactively.

package.nls.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,5 +216,14 @@
216216
"AWS.walkthrough.gettingStarted.connect": "Connect to AWS",
217217
"AWS.walkthrough.gettingStarted.changeRegions": "Change AWS Regions",
218218
"AWS.walkthrough.gettingStarted.setupToolchain": "Configure your toolchain",
219-
"AWS.command.codewhisperer.title": "CodeWhisperer Invoke Service"
219+
"AWS.command.codewhisperer.title": "CodeWhisperer Invoke Service",
220+
"AWS.explorerNode.selectCustomization.label": "Select a Customization",
221+
"AWS.codewhisperer.customization.base.label": "CodeWhisperer foundation (Default)",
222+
"AWS.codewhisperer.customization.base.description": "default",
223+
"AWS.codewhisperer.customization.base.detail": "Receive suggestions from CodeWhisperer base model",
224+
"AWS.codewhisperer.customization.selected": "Connected",
225+
"AWS.codewhisperer.customization.quickPick.title": "Select a Customization",
226+
"AWS.codewhisperer.customization.quickPick.placeholder": "You have access to the following customizations",
227+
"AWS.codewhisperer.customization.notification.new_customizations.select": "Select Customization",
228+
"AWS.codewhisperer.customization.notification.new_customizations.learn_more": "Learn More"
220229
}

src/codewhisperer/activation.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ import {
3333
showIntroduction,
3434
reconnect,
3535
refreshStatusBar,
36+
selectCustomization,
37+
notifyNewCustomizationsCmd,
38+
connectIdCenter,
3639
} from './commands/basicCommands'
3740
import { sleep } from '../shared/utilities/timeoutUtils'
3841
import { ReferenceLogViewProvider } from './service/referenceLogViewProvider'
@@ -49,6 +52,7 @@ import { AuthUtil } from './util/authUtil'
4952
import { ImportAdderProvider } from './service/importAdderProvider'
5053
import { TelemetryHelper } from './util/telemetryHelper'
5154
import { openUrl } from '../shared/utilities/vsCodeUtils'
55+
import { notifyNewCustomizations } from './util/customizationUtil'
5256
import { CodeWhispererCommandBackend, CodeWhispererCommandDeclarations } from './commands/gettingStartedPageCommands'
5357
const performance = globalThis.performance ?? require('perf_hooks').performance
5458

@@ -155,6 +159,8 @@ export async function activate(context: ExtContext): Promise<void> {
155159
}),
156160
// show introduction
157161
showIntroduction.register(),
162+
// CodeWhisperer Identity Center connection setup
163+
connectIdCenter.register(),
158164
// toggle code suggestions
159165
toggleCodeSuggestions.register(context.extensionContext.globalState),
160166
// enable code suggestions
@@ -177,6 +183,10 @@ export async function activate(context: ExtContext): Promise<void> {
177183
Commands.register({ id: 'aws.codeWhisperer', autoconnect: true }, async () => {
178184
invokeRecommendation(vscode.window.activeTextEditor as vscode.TextEditor, client, await getConfigEntry())
179185
}),
186+
// select customization
187+
selectCustomization.register(),
188+
// notify new customizations
189+
notifyNewCustomizationsCmd.register(),
180190
/**
181191
* On recommendation acceptance
182192
*/
@@ -210,6 +220,9 @@ export async function activate(context: ExtContext): Promise<void> {
210220
if (auth.isConnectionExpired()) {
211221
auth.showReauthenticatePrompt()
212222
}
223+
if (auth.isValidEnterpriseSsoInUse()) {
224+
await notifyNewCustomizations()
225+
}
213226

214227
function activateSecurityScan() {
215228
context.extensionContext.subscriptions.push(

src/codewhisperer/client/codewhisperer.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
5-
import { AWSError, Service } from 'aws-sdk'
6-
import apiConfig = require('./service-2.json')
7-
import userApiConfig = require('./user-service-2.json')
5+
import { AWSError, Credentials, Service } from 'aws-sdk'
86
import globals from '../../shared/extensionGlobals'
97
import * as CodeWhispererClient from './codewhispererclient'
108
import * as CodeWhispererUserClient from './codewhispereruserclient'
9+
import { ListAvailableCustomizationsResponse, SendTelemetryEventRequest } from './codewhispereruserclient'
1110
import * as CodeWhispererConstants from '../models/constants'
1211
import { ServiceOptions } from '../../shared/awsClientBuilder'
1312
import { isCloud9 } from '../../shared/extensionUtilities'
1413
import { CodeWhispererSettings } from '../util/codewhispererSettings'
1514
import { PromiseResult } from 'aws-sdk/lib/request'
16-
import { Credentials } from 'aws-sdk'
1715
import { AuthUtil } from '../util/authUtil'
1816
import { isSsoConnection } from '../../auth/connection'
17+
import { pageableToCollection } from '../../shared/utilities/collectionUtils'
18+
import apiConfig = require('./service-2.json')
19+
import userApiConfig = require('./user-service-2.json')
1920
import { session } from '../util/codeWhispererSession'
20-
import { SendTelemetryEventRequest } from './codewhispereruserclient'
2121
import { getLogger } from '../../shared/logger'
2222

2323
export type ProgrammingLanguage = Readonly<
@@ -192,6 +192,13 @@ export class DefaultCodeWhispererClient {
192192
.promise()
193193
}
194194

195+
public async listAvailableCustomizations(): Promise<ListAvailableCustomizationsResponse[]> {
196+
const client = await this.createUserSdkClient()
197+
const requester = async (request: CodeWhispererUserClient.ListAvailableCustomizationsRequest) =>
198+
client.listAvailableCustomizations(request).promise()
199+
return pageableToCollection(requester, {}, 'nextToken').promise()
200+
}
201+
195202
public async sendTelemetryEvent(request: SendTelemetryEventRequest) {
196203
const requestWithOptOut: SendTelemetryEventRequest = {
197204
...request,

src/codewhisperer/client/user-service-2.json

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,21 @@
7575
{ "shape": "AccessDeniedException" }
7676
]
7777
},
78+
"ListAvailableCustomizations": {
79+
"name": "ListAvailableCustomizations",
80+
"http": {
81+
"method": "POST",
82+
"requestUri": "/"
83+
},
84+
"input": { "shape": "ListAvailableCustomizationsRequest" },
85+
"output": { "shape": "ListAvailableCustomizationsResponse" },
86+
"errors": [
87+
{ "shape": "ThrottlingException" },
88+
{ "shape": "InternalServerException" },
89+
{ "shape": "ValidationException" },
90+
{ "shape": "AccessDeniedException" }
91+
]
92+
},
7893
"ListCodeAnalysisFindings": {
7994
"name": "ListCodeAnalysisFindings",
8095
"http": {
@@ -164,6 +179,7 @@
164179
"type": "structure",
165180
"required": ["programmingLanguage", "acceptedCharacterCount", "totalCharacterCount", "timestamp"],
166181
"members": {
182+
"customizationArn": { "shape": "ResourceArn" },
167183
"programmingLanguage": { "shape": "ProgrammingLanguage" },
168184
"acceptedCharacterCount": { "shape": "SensitiveInteger" },
169185
"totalCharacterCount": { "shape": "SensitiveInteger" },
@@ -240,6 +256,34 @@
240256
"kmsKeyArn": { "shape": "ResourceArn" }
241257
}
242258
},
259+
"Customization": {
260+
"type": "structure",
261+
"required": ["arn"],
262+
"members": {
263+
"arn": { "shape": "ResourceArn" },
264+
"name": { "shape": "CustomizationName" },
265+
"description": { "shape": "Description" }
266+
}
267+
},
268+
"CustomizationName": {
269+
"type": "string",
270+
"max": 100,
271+
"min": 1,
272+
"pattern": "[a-zA-Z][a-zA-Z0-9_-]*"
273+
},
274+
"Customizations": {
275+
"type": "list",
276+
"member": { "shape": "Customization" }
277+
},
278+
"Description": {
279+
"type": "string",
280+
"max": 256,
281+
"min": 0
282+
},
283+
"Double": {
284+
"type": "double",
285+
"box": true
286+
},
243287
"FileContext": {
244288
"type": "structure",
245289
"required": ["leftFileContent", "rightFileContent", "filename", "programmingLanguage"],
@@ -276,7 +320,8 @@
276320
"maxResults": { "shape": "GenerateCompletionsRequestMaxResultsInteger" },
277321
"nextToken": { "shape": "GenerateCompletionsRequestNextTokenString" },
278322
"referenceTrackerConfiguration": { "shape": "ReferenceTrackerConfiguration" },
279-
"supplementalContexts": { "shape": "SupplementalContextList" }
323+
"supplementalContexts": { "shape": "SupplementalContextList" },
324+
"customizationArn": { "shape": "ResourceArn" }
280325
}
281326
},
282327
"GenerateCompletionsRequestMaxResultsInteger": {
@@ -351,6 +396,27 @@
351396
"fault": true,
352397
"retryable": { "throttling": false }
353398
},
399+
"ListAvailableCustomizationsRequest": {
400+
"type": "structure",
401+
"members": {
402+
"maxResults": { "shape": "ListAvailableCustomizationsRequestMaxResultsInteger" },
403+
"nextToken": { "shape": "Base64EncodedPaginationToken" }
404+
}
405+
},
406+
"ListAvailableCustomizationsRequestMaxResultsInteger": {
407+
"type": "integer",
408+
"box": true,
409+
"max": 100,
410+
"min": 1
411+
},
412+
"ListAvailableCustomizationsResponse": {
413+
"type": "structure",
414+
"required": ["customizations"],
415+
"members": {
416+
"customizations": { "shape": "Customizations" },
417+
"nextToken": { "shape": "Base64EncodedPaginationToken" }
418+
}
419+
},
354420
"ListCodeAnalysisFindingsRequest": {
355421
"type": "structure",
356422
"required": ["jobId", "codeAnalysisFindingsSchema"],
@@ -598,6 +664,7 @@
598664
"requestId": { "shape": "UUID" },
599665
"programmingLanguage": { "shape": "ProgrammingLanguage" },
600666
"modificationPercentage": { "shape": "SensitiveDouble" },
667+
"customizationArn": { "shape": "ResourceArn" },
601668
"timestamp": { "shape": "Timestamp" }
602669
}
603670
},
@@ -615,6 +682,7 @@
615682
"members": {
616683
"sessionId": { "shape": "UUID" },
617684
"requestId": { "shape": "UUID" },
685+
"customizationArn": { "shape": "ResourceArn" },
618686
"programmingLanguage": { "shape": "ProgrammingLanguage" },
619687
"completionType": { "shape": "CompletionType" },
620688
"suggestionState": { "shape": "SuggestionState" },

src/codewhisperer/commands/basicCommands.ts

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@ import { telemetry } from '../../shared/telemetry/telemetry'
88
import { ExtContext } from '../../shared/extensions'
99
import { Commands } from '../../shared/vscode/commands2'
1010
import * as CodeWhispererConstants from '../models/constants'
11-
import { getLogger } from '../../shared/logger'
1211
import { DefaultCodeWhispererClient } from '../client/codewhisperer'
1312
import { startSecurityScanWithProgress, confirmStopSecurityScan } from './startSecurityScan'
1413
import { SecurityPanelViewProvider } from '../views/securityPanelViewProvider'
1514
import { codeScanState } from '../models/model'
15+
import { connectToEnterpriseSso, getStartUrl } from '../util/getStartUrl'
1616
import { showConnectionPrompt } from '../util/showSsoPrompt'
1717
import { ReferenceLogViewProvider } from '../service/referenceLogViewProvider'
1818
import { AuthUtil } from '../util/authUtil'
1919
import { isCloud9 } from '../../shared/extensionUtilities'
2020
import { InlineCompletionService } from '../service/inlineCompletionService'
2121
import { openUrl } from '../../shared/utilities/vsCodeUtils'
22+
import { notifyNewCustomizations, showCustomizationPrompt } from '../util/customizationUtil'
23+
import { get, set } from '../util/commonUtil'
2224
import { CodeWhispererCommandDeclarations } from '../commands/gettingStartedPageCommands'
2325
import { getIcon } from '../../shared/icons'
2426
import { localize } from '../../shared/utilities/vsCodeUtils'
@@ -98,28 +100,36 @@ export const showSecurityScan = Commands.declare(
98100
}
99101
)
100102

103+
export const selectCustomization = Commands.declare('aws.codeWhisperer.selectCustomization', () => async () => {
104+
telemetry.ui_click.emit({ elementId: 'cw_selectCustomization_Cta' })
105+
showCustomizationPrompt().then()
106+
})
107+
101108
export const reconnect = Commands.declare('aws.codeWhisperer.reconnect', () => async () => {
102109
await AuthUtil.instance.reauthenticate()
103110
})
104111

105-
export function get(key: string, context: vscode.Memento): any {
106-
return context.get(key)
107-
}
108-
109-
export async function set(key: string, value: any, context: vscode.Memento): Promise<void> {
110-
await context.update(key, value).then(
111-
() => {},
112-
error => {
113-
getLogger().verbose(`Failed to update global state: ${error}`)
114-
}
115-
)
116-
}
117-
118112
export const showSsoSignIn = Commands.declare('aws.codeWhisperer.sso', () => async () => {
119113
telemetry.ui_click.emit({ elementId: 'cw_signUp_Cta' })
120114
await showConnectionPrompt()
121115
})
122116

117+
// Shortcut command to directly connect to Identity Center or prompt start URL entry
118+
// Customization is not yet supported.
119+
export const connectIdCenter = Commands.declare(
120+
'aws.codeWhisperer.connect',
121+
() => async (startUrl?: string, region?: string) => {
122+
// This command expects two arguments: startUrl and region (both strings).
123+
// If these arguments are provided, they will be used.
124+
// Otherwise, the commands prompts for them interactively.
125+
if (startUrl && region) {
126+
await connectToEnterpriseSso(startUrl, region)
127+
} else {
128+
await getStartUrl()
129+
}
130+
}
131+
)
132+
123133
export const showLearnMore = Commands.declare('aws.codeWhisperer.learnMore', () => async () => {
124134
telemetry.ui_click.emit({ elementId: 'cw_learnMore_Cta' })
125135
openUrl(vscode.Uri.parse(CodeWhispererConstants.learnMoreUriGeneral))
@@ -149,3 +159,10 @@ export const refreshStatusBar = Commands.declare(
149159
}
150160
}
151161
)
162+
163+
export const notifyNewCustomizationsCmd = Commands.declare(
164+
{ id: 'aws.codeWhisperer.notifyNewCustomizations', logging: false },
165+
() => () => {
166+
notifyNewCustomizations().then()
167+
}
168+
)

src/codewhisperer/explorer/codewhispererChildrenNodes.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ import {
1414
showLearnMore,
1515
showFreeTierLimit,
1616
reconnect,
17+
selectCustomization,
1718
} from '../commands/basicCommands'
1819
import { codeScanState } from '../models/model'
20+
import { getNewCustomizationAvailable, getSelectedCustomization } from '../util/customizationUtil'
1921

2022
export const createEnableCodeSuggestionsNode = () =>
2123
enableCodeSuggestions.build().asTreeNode({
@@ -88,3 +90,15 @@ export const createFreeTierLimitMetNode = () => {
8890
description: localize('AWS.explorerNode.freeTierLimitMet.tooltip', `paused until ${nextMonth}`),
8991
})
9092
}
93+
94+
export const createSelectCustomizationNode = () => {
95+
const newCustomizationsAvailable = getNewCustomizationAvailable()
96+
const selectedCustomization = getSelectedCustomization()
97+
const newText = newCustomizationsAvailable ? 'new! ' : ''
98+
99+
return selectCustomization.build().asTreeNode({
100+
label: localize('AWS.explorerNode.selectCustomization.label', 'Select Customization'),
101+
iconPath: getIcon('vscode-extensions'),
102+
description: `${newText}${selectedCustomization.arn === '' ? '' : selectedCustomization.name}`,
103+
})
104+
}

src/codewhisperer/explorer/codewhispererNode.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
createSsoSignIn,
1515
createFreeTierLimitMetNode,
1616
createReconnectNode,
17+
createSelectCustomizationNode,
1718
} from './codewhispererChildrenNodes'
1819
import { createGettingStartedNode } from '../commands/basicCommands'
1920
import { Commands } from '../../shared/vscode/commands2'
@@ -84,6 +85,14 @@ export class CodeWhispererNode implements RootNode {
8485
if (isCloud9()) {
8586
return [createAutoSuggestionsNode(autoTriggerEnabled), createOpenReferenceLogNode()]
8687
} else {
88+
if (AuthUtil.instance.isValidEnterpriseSsoInUse() && AuthUtil.instance.isCustomizationFeatureEnabled) {
89+
return [
90+
createAutoSuggestionsNode(autoTriggerEnabled),
91+
createSecurityScanNode(),
92+
createSelectCustomizationNode(),
93+
createOpenReferenceLogNode(),
94+
]
95+
}
8796
return [
8897
createAutoSuggestionsNode(autoTriggerEnabled),
8998
createSecurityScanNode(),

0 commit comments

Comments
 (0)