Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions docs/build.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
# Build

The AmazonQ features rely on the `codewhisperer-streaming` service, who's client
is generated from the service's smithy models and placed in
`src.gen/@amzn/codewhisperer-streaming` (For more
information about this client and how it is generated, please see this
The AmazonQ features rely on the `codewhisperer-streaming` service, to support both Sigv4 and Bearer token modes of this service,
two clients are generated from the service's smithy models and placed in
`src.gen/@amzn/amazon-q-developer-streaming-client` and `src.gen/@amzn/codewhisperer-streaming` respectively (For more
information about these clients and how they are generated, please see this
[quip document](https://quip-amazon.com/2dAWAvTIYXXr/Build-instructions-for-AWS-CodeWhisperer-Streaming-Typescript-client)).

## @amzn/amazon-q-developer-streaming client

This client is a standalone npm project in typescript, and it is added to
the project as a workspace in the project's root `package.json` with the line `"workspaces": [ ..., "src.gen/@amzn/amazon-q-developer-streaming" ]`.
The client may be manually built using `npm run build -w @amzn/amazon-q-developer-streaming"`.
The `generateClients` run script ensures that this dependency is
built before the toolkit project itself. Workspaces are automatically ready to
be imported in the root toolkit project by their declared package.json name,
(`@amzn/amazon-q-developer-streaming` in this case).

## @amzn/codewhisperer-streaming client

This client is a standalone npm project in typescript, and it is added to
the project as a workspace in the project's root `package.json` with the line `"workspaces": [ ..., "src.gen/@amzn/codewhisperer-streaming" ]`.
The client may be manually built using `npm run build -w @amzn/codewhisperer-streaming"`.
Expand Down
20,231 changes: 10,544 additions & 9,687 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
},
"scripts": {
"prepare": "ts-node ./scripts/prepare.ts",
"preinstall": "cd src.gen/@amzn/codewhisperer-streaming && npm i",
"preinstall": "cd src.gen/@amzn/codewhisperer-streaming && npm i && cd ../amazon-q-developer-streaming-client && npm i",
"postinstall": "npm run buildCustomLintPlugin && npm run postinstall -ws --if-present",
"buildCustomLintPlugin": "npm run build -w plugins/eslint-plugin-aws-toolkits",
"compile": "npm run compile -w packages/",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "Bug Fix",
"description": "Use Sagemaker environment IAM Credentials for Code Completion when they're available"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "Bug Fix",
"description": "Inline: Code completion not working for Sagemaker Pro Tier users."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "Bug Fix",
"description": "Disable /transform and /dev commands for sagemaker users as they're not supported"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "Feature",
"description": "Enable Free Tier Chat for IAM users"
}
4 changes: 2 additions & 2 deletions packages/amazonq/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,13 @@
"type": "webview",
"id": "aws.amazonq.AmazonCommonAuth",
"name": "%AWS.amazonq.login%",
"when": "!aws.isSageMaker && !aws.isWebExtHost && aws.amazonq.showLoginView"
"when": "!aws.isWebExtHost && aws.amazonq.showLoginView"
},
{
"type": "webview",
"id": "aws.AmazonQChatView",
"name": "%AWS.amazonq.chat%",
"when": "!aws.isSageMaker && !aws.isWebExtHost && !aws.amazonq.showLoginView"
"when": "!aws.isWebExtHost && !aws.amazonq.showLoginView"
},
{
"id": "aws.AmazonQNeverShowBadge",
Expand Down
7 changes: 6 additions & 1 deletion packages/amazonq/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { SendMessageCommandOutput, SendMessageRequest } from '@amzn/amazon-q-developer-streaming-client'
import { GenerateAssistantResponseCommandOutput, GenerateAssistantResponseRequest } from '@amzn/codewhisperer-streaming'
import { AuthUtil } from 'aws-core-vscode/codewhisperer'
import { ChatSession } from 'aws-core-vscode/codewhispererChat'
Expand All @@ -12,7 +13,11 @@ export default {
chatApi: {
async chat(request: GenerateAssistantResponseRequest): Promise<GenerateAssistantResponseCommandOutput> {
const chatSession = new ChatSession()
return chatSession.chat(request)
return chatSession.chatSso(request)
},
async chatIam(request: SendMessageRequest): Promise<SendMessageCommandOutput> {
const chatSession = new ChatSession()
return chatSession.chatIam(request)
},
},
authApi: {
Expand Down
3 changes: 2 additions & 1 deletion packages/amazonq/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
setContext,
setupUninstallHandler,
maybeShowMinVscodeWarning,
isSageMaker,
} from 'aws-core-vscode/shared'
import { ExtStartUpSources, telemetry } from 'aws-core-vscode/telemetry'
import { VSCODE_EXTENSION_ID } from 'aws-core-vscode/utils'
Expand Down Expand Up @@ -193,7 +194,7 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is
}
}
const currConn = AuthUtil.instance.conn
if (currConn !== undefined && !isAnySsoConnection(currConn)) {
if (currConn !== undefined && !(isAnySsoConnection(currConn) || isSageMaker())) {
getLogger().error(`Current Amazon Q connection is not SSO, type is: %s`, currConn?.type)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,16 @@ import { computeDecorations } from '../decorations/computeDecorations'
import { CodelensProvider } from '../codeLenses/codeLenseProvider'
import { PromptMessage, ReferenceLogController } from 'aws-core-vscode/codewhispererChat'
import { CodeWhispererSettings } from 'aws-core-vscode/codewhisperer'
import { codicon, getIcon, getLogger, messages, setContext, Timeout, textDocumentUtil } from 'aws-core-vscode/shared'
import {
codicon,
getIcon,
getLogger,
messages,
setContext,
Timeout,
textDocumentUtil,
isSageMaker,
} from 'aws-core-vscode/shared'
import { InlineLineAnnotationController } from '../decorations/inlineLineAnnotationController'

export class InlineChatController {
Expand Down Expand Up @@ -162,6 +171,11 @@ export class InlineChatController {
return
}

if (isSageMaker()) {
void vscode.window.showWarningMessage('Amazon Q: Inline chat is not supported in Sagemaker')
return
}

if (this.task && this.task.isActiveState()) {
void vscode.window.showWarningMessage(
'Amazon Q: Reject or Accept the current suggestion before creating a new one'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export class InlineChatProvider {
let response: GenerateAssistantResponseCommandOutput | undefined = undefined
session.createNewTokenSource()
try {
response = await session.chat(request)
response = await session.chatSso(request)
getLogger().info(
`response to tab: ${tabID} conversationID: ${session.sessionIdentifier} requestID: ${response.$metadata.requestId} metadata: ${JSON.stringify(
response.$metadata
Expand Down
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@
"webfont": "^11.2.26"
},
"dependencies": {
"@amzn/amazon-q-developer-streaming-client": "file:../../src.gen/@amzn/amazon-q-developer-streaming-client",
"@amzn/codewhisperer-streaming": "file:../../src.gen/@amzn/codewhisperer-streaming",
"@aws-sdk/client-cognito-identity": "^3.637.0",
"@aws-sdk/client-lambda": "^3.637.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/amazonq/extApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import vscode from 'vscode'
import { VSCODE_EXTENSION_ID } from '../shared/utilities'
import { SendMessageCommandOutput, SendMessageRequest } from '@amzn/amazon-q-developer-streaming-client'
import { GenerateAssistantResponseCommandOutput, GenerateAssistantResponseRequest } from '@amzn/codewhisperer-streaming'
import { FeatureAuthState } from '../codewhisperer/util/authUtil'
import { ToolkitError } from '../shared'
Expand All @@ -16,6 +17,7 @@ import { ToolkitError } from '../shared'
export interface api {
chatApi: {
chat(request: GenerateAssistantResponseRequest): Promise<GenerateAssistantResponseCommandOutput>
chatIam(request: SendMessageRequest): Promise<SendMessageCommandOutput>
}
authApi: {
reauthIfNeeded(): Promise<void>
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/amazonq/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@ import { FeatureContext } from '../shared'
export function createMynahUI(
ideApi: any,
amazonQEnabled: boolean,
featureConfigsSerialized: [string, FeatureContext][]
featureConfigsSerialized: [string, FeatureContext][],
disabledCommands?: string[]
) {
if (typeof window !== 'undefined') {
const mynahUI = require('./webview/ui/main')
return mynahUI.createMynahUI(ideApi, amazonQEnabled, featureConfigsSerialized)
return mynahUI.createMynahUI(ideApi, amazonQEnabled, featureConfigsSerialized, disabledCommands)
}
throw new Error('Not implemented for node')
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import path from 'path'
import { Uri, Webview } from 'vscode'
import { AuthUtil } from '../../../codewhisperer/util/authUtil'
import { FeatureConfigProvider, FeatureContext, globals } from '../../../shared'
import { FeatureConfigProvider, FeatureContext, globals, isSageMaker } from '../../../shared'

export class WebViewContentGenerator {
private async generateFeatureConfigsData(): Promise<string> {
Expand Down Expand Up @@ -77,14 +77,16 @@ export class WebViewContentGenerator {
// Fetch featureConfigs and use it within the script
const featureConfigsString = await this.generateFeatureConfigsData()

const disabledCommandsString = isSageMaker() ? `['/dev', '/transform']` : '[]'

return `
<script type="text/javascript" src="${javascriptEntrypoint.toString()}" defer onload="init()"></script>
${cssLinks}
<script type="text/javascript">
const init = () => {
createMynahUI(acquireVsCodeApi(), ${
(await AuthUtil.instance.getChatAuthState()).amazonQ === 'connected'
},${featureConfigsString});
},${featureConfigsString},${disabledCommandsString});
}
</script>
`
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/amazonq/webview/ui/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import { tryNewMap } from '../../util/functionUtils'
export const createMynahUI = (
ideApi: any,
amazonQEnabled: boolean,
featureConfigsSerialized: [string, FeatureContext][]
featureConfigsSerialized: [string, FeatureContext][],
disabledCommands?: string[]
) => {
// eslint-disable-next-line prefer-const
let mynahUI: MynahUI
Expand Down Expand Up @@ -77,6 +78,7 @@ export const createMynahUI = (
let tabDataGenerator = new TabDataGenerator({
isFeatureDevEnabled,
isGumbyEnabled,
disabledCommands,
})

// eslint-disable-next-line prefer-const
Expand Down Expand Up @@ -118,11 +120,13 @@ export const createMynahUI = (
tabsStorage,
isFeatureDevEnabled,
isGumbyEnabled,
disabledCommands,
})

tabDataGenerator = new TabDataGenerator({
isFeatureDevEnabled,
isGumbyEnabled,
disabledCommands,
})

featureConfigs = tryNewMap(featureConfigsSerialized)
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/amazonq/webview/ui/messages/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface MessageControllerProps {
tabsStorage: TabsStorage
isFeatureDevEnabled: boolean
isGumbyEnabled: boolean
disabledCommands?: string[]
}

export class MessageController {
Expand All @@ -30,6 +31,7 @@ export class MessageController {
this.tabDataGenerator = new TabDataGenerator({
isFeatureDevEnabled: props.isFeatureDevEnabled,
isGumbyEnabled: props.isGumbyEnabled,
disabledCommands: props.disabledCommands,
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,25 @@ import { TabType } from '../storages/tabsStorage'
export interface QuickActionGeneratorProps {
isFeatureDevEnabled: boolean
isGumbyEnabled: boolean
disableCommands?: string[]
}

export class QuickActionGenerator {
public isFeatureDevEnabled: boolean
private isGumbyEnabled: boolean
private disabledCommands: string[]

constructor(props: QuickActionGeneratorProps) {
this.isFeatureDevEnabled = props.isFeatureDevEnabled
this.isGumbyEnabled = props.isGumbyEnabled
this.disabledCommands = props.disableCommands ?? []
}

public generateForTab(tabType: TabType): QuickActionCommandGroup[] {
const quickActionCommands = [
{
commands: [
...(this.isFeatureDevEnabled
...(this.isFeatureDevEnabled && !this.disabledCommands.includes('/dev')
? [
{
command: '/dev',
Expand All @@ -33,7 +36,7 @@ export class QuickActionGenerator {
},
]
: []),
...(this.isGumbyEnabled
...(this.isGumbyEnabled && !this.disabledCommands.includes('/transform')
? [
{
command: '/transform',
Expand All @@ -55,7 +58,7 @@ export class QuickActionGenerator {
},
],
},
]
].filter((section) => section.commands.length > 0)

const commandUnavailability: Record<
TabType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface QuickActionsHandlerProps {
tabsStorage: TabsStorage
isFeatureDevEnabled: boolean
isGumbyEnabled: boolean
disabledCommands?: string[]
}

export class QuickActionHandler {
Expand All @@ -32,6 +33,7 @@ export class QuickActionHandler {
this.tabDataGenerator = new TabDataGenerator({
isFeatureDevEnabled: props.isFeatureDevEnabled,
isGumbyEnabled: props.isGumbyEnabled,
disabledCommands: props.disabledCommands,
})
this.isFeatureDevEnabled = props.isFeatureDevEnabled
this.isGumbyEnabled = props.isGumbyEnabled
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/amazonq/webview/ui/tabs/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { TabTypeDataMap } from './constants'
export interface TabDataGeneratorProps {
isFeatureDevEnabled: boolean
isGumbyEnabled: boolean
disabledCommands?: string[]
}

export class TabDataGenerator {
Expand All @@ -23,6 +24,7 @@ export class TabDataGenerator {
this.quickActionsGenerator = new QuickActionGenerator({
isFeatureDevEnabled: props.isFeatureDevEnabled,
isGumbyEnabled: props.isGumbyEnabled,
disableCommands: props.disabledCommands,
})
}

Expand Down
16 changes: 14 additions & 2 deletions packages/core/src/auth/activation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,28 @@
* SPDX-License-Identifier: Apache-2.0
*/

import * as vscode from 'vscode'
import { Auth } from './auth'
import { LoginManager } from './deprecated/loginManager'
import { fromString } from './providers/credentials'
import { getLogger } from '../shared/logger'
import { ExtensionUse } from './utils'
import { isCloud9 } from '../shared/extensionUtilities'
import { ExtensionUse, initializeCredentialsProviderManager } from './utils'
import { isAmazonQ, isCloud9, isSageMaker } from '../shared/extensionUtilities'
import { isInDevEnv } from '../shared/vscode/env'
import { isWeb } from '../shared/extensionGlobals'

interface SagemakerCookie {
authMode?: 'Sso' | 'Iam'
}

export async function initialize(loginManager: LoginManager): Promise<void> {
if (isAmazonQ() && isSageMaker()) {
// The command `sagemaker.parseCookies` is registered in VS Code Sagemaker environment.
const result = (await vscode.commands.executeCommand('sagemaker.parseCookies')) as SagemakerCookie
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this command come from? Is it already registered in VSC by sagemaker? If so add a comment to mention this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, this command is registered in Sagemaker code editor. I'll add a comment

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets make a new sagemaker folder in src/shared/sagemaker for all custom sagemaker code so that it is contained within a single place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a big refactor that I'd rather defer to a later followup to reduce risk

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a long-term approach. The Toolkit/Q extensions already have an api to accept connections. If needed, they can be enhanced to accept tokens/credentials, so the caller (SM in this case) can inject credentials into the extension.

if (result.authMode !== 'Sso') {
initializeCredentialsProviderManager()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does this refactor affect toolkit ? In sagemaker studio sso mode, toolkit will still work in IAM mode.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The higher level condition is scoped to amazonq, so it shouldn't impact aws toolkit

}
}
Auth.instance.onDidChangeActiveConnection(async (conn) => {
// This logic needs to be moved to `Auth.useConnection` to correctly record `passive`
if (conn?.type === 'iam' && conn.state === 'valid') {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export {
isAnySsoConnection,
isBuilderIdConnection,
getTelemetryMetadataForConn,
isIamConnection,
} from './connection'
export { Auth } from './auth'
export { CredentialsStore } from './credentials/store'
Expand Down
Loading
Loading