Skip to content

Commit 370a9a1

Browse files
committed
Merge remote-tracking branch 'upstream/master' into nep-prefix
2 parents 6ea4a29 + 7a03794 commit 370a9a1

File tree

19 files changed

+1019
-437
lines changed

19 files changed

+1019
-437
lines changed

package-lock.json

Lines changed: 191 additions & 333 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
@@ -75,7 +75,7 @@
7575
"webpack-merge": "^5.10.0"
7676
},
7777
"dependencies": {
78-
"@aws/language-server-runtimes": "^0.2.128",
78+
"@aws/language-server-runtimes": "^0.3.5",
7979
"@types/node": "^22.7.5",
8080
"jaro-winkler": "^0.2.8",
8181
"vscode-nls": "^5.2.0",
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"date": "2025-11-06",
3+
"version": "1.103.0",
4+
"entries": [
5+
{
6+
"type": "Feature",
7+
"description": "Q CodeTransformation: add more job metadata to history table"
8+
}
9+
]
10+
}

packages/amazonq/.changes/next-release/Feature-ab31cbb6-3fe4-4ee3-a0a3-290430277856.json

Lines changed: 0 additions & 4 deletions
This file was deleted.

packages/amazonq/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 1.103.0 2025-11-06
2+
3+
- **Feature** Q CodeTransformation: add more job metadata to history table
4+
15
## 1.102.0 2025-10-30
26

37
- Miscellaneous non-user-facing changes

packages/amazonq/src/app/inline/completion.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
getDiagnosticsOfCurrentFile,
3838
toIdeDiagnostics,
3939
handleExtraBrackets,
40+
InlineCompletionLoggingReason,
4041
} from 'aws-core-vscode/codewhisperer'
4142
import { LineTracker } from './stateTracker/lineTracker'
4243
import { InlineTutorialAnnotation } from './tutorials/inlineTutorialAnnotation'
@@ -429,6 +430,7 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
429430
discarded: !prevSession.displayed,
430431
},
431432
},
433+
reason: InlineCompletionLoggingReason.IMPLICIT_REJECT,
432434
firstCompletionDisplayLatency: prevSession.firstCompletionDisplayLatency,
433435
totalSessionDisplayTime: Date.now() - prevSession.requestStartTime,
434436
}

packages/core/src/awsService/sagemaker/commands.ts

Lines changed: 207 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,19 @@ import _ from 'lodash'
1616
import { prepareDevEnvConnection, tryRemoteConnection } from './model'
1717
import { ExtContext } from '../../shared/extensions'
1818
import { SagemakerClient } from '../../shared/clients/sagemaker'
19+
import { AccessDeniedException } from '@amzn/sagemaker-client'
1920
import { ToolkitError } from '../../shared/errors'
2021
import { showConfirmationMessage } from '../../shared/utilities/messages'
2122
import { RemoteSessionError } from '../../shared/remoteSession'
22-
import { ConnectFromRemoteWorkspaceMessage, InstanceTypeError } from './constants'
23+
import {
24+
ConnectFromRemoteWorkspaceMessage,
25+
InstanceTypeError,
26+
InstanceTypeInsufficientMemory,
27+
InstanceTypeInsufficientMemoryMessage,
28+
RemoteAccess,
29+
RemoteAccessRequiredMessage,
30+
SpaceStatus,
31+
} from './constants'
2332
import { SagemakerUnifiedStudioSpaceNode } from '../../sagemakerunifiedstudio/explorer/nodes/sageMakerUnifiedStudioSpaceNode'
2433

2534
const localize = nls.loadMessageBundle()
@@ -136,10 +145,10 @@ export async function stopSpace(
136145
sageMakerClient?: SagemakerClient
137146
) {
138147
await tryRefreshNode(node)
139-
if (node.getStatus() === 'Stopped' || node.getStatus() === 'Stopping') {
148+
if (node.getStatus() === SpaceStatus.STOPPED || node.getStatus() === SpaceStatus.STOPPING) {
140149
void vscode.window.showWarningMessage(`Space ${node.spaceApp.SpaceName} is already in Stopped/Stopping state.`)
141150
return
142-
} else if (node.getStatus() === 'Starting') {
151+
} else if (node.getStatus() === SpaceStatus.STARTING) {
143152
void vscode.window.showWarningMessage(
144153
`Space ${node.spaceApp.SpaceName} is in Starting state. Wait until it is Running to attempt stop again.`
145154
)
@@ -162,12 +171,12 @@ export async function stopSpace(
162171
await client.deleteApp({
163172
DomainId: node.spaceApp.DomainId!,
164173
SpaceName: spaceName,
165-
AppType: node.spaceApp.App!.AppType!,
174+
AppType: node.spaceApp.SpaceSettingsSummary!.AppType!,
166175
AppName: node.spaceApp.App?.AppName,
167176
})
168177
} catch (err) {
169178
const error = err as Error
170-
if (error.name === 'AccessDeniedException') {
179+
if (error instanceof AccessDeniedException) {
171180
throw new ToolkitError('You do not have permission to stop spaces. Please contact your administrator', {
172181
cause: error,
173182
code: error.name,
@@ -195,56 +204,213 @@ export async function openRemoteConnect(
195204
const spaceName = node.spaceApp.SpaceName!
196205
await tryRefreshNode(node)
197206

198-
// for Stopped SM spaces - check instance type before showing progress
199-
if (node.getStatus() === 'Stopped') {
200-
// In case of SMUS, we pass in a SM Client and for SM AI, it creates a new SM Client.
201-
const client = sageMakerClient ? sageMakerClient : new SagemakerClient(node.regionCode)
202-
203-
try {
204-
await client.startSpace(spaceName, node.spaceApp.DomainId!)
205-
await tryRefreshNode(node)
206-
const appType = node.spaceApp.SpaceSettingsSummary?.AppType
207-
if (!appType) {
208-
throw new ToolkitError('AppType is undefined for the selected space. Cannot start remote connection.', {
209-
code: 'undefinedAppType',
210-
})
207+
const remoteAccess = node.spaceApp.SpaceSettingsSummary?.RemoteAccess
208+
const nodeStatus = node.getStatus()
209+
210+
// Route to appropriate handler based on space state
211+
if (nodeStatus === SpaceStatus.RUNNING && remoteAccess !== RemoteAccess.ENABLED) {
212+
return handleRunningSpaceWithDisabledAccess(node, ctx, spaceName, sageMakerClient)
213+
} else if (nodeStatus === SpaceStatus.STOPPED) {
214+
return handleStoppedSpace(node, ctx, spaceName, sageMakerClient)
215+
} else if (nodeStatus === SpaceStatus.RUNNING) {
216+
return handleRunningSpaceWithEnabledAccess(node, ctx, spaceName)
217+
}
218+
}
219+
220+
/**
221+
* Checks if an instance type upgrade will be needed for remote access
222+
*/
223+
export async function checkInstanceTypeUpgradeNeeded(
224+
node: SagemakerSpaceNode | SagemakerUnifiedStudioSpaceNode,
225+
sageMakerClient?: SagemakerClient
226+
): Promise<{ upgradeNeeded: boolean; currentType?: string; recommendedType?: string }> {
227+
const client = sageMakerClient || new SagemakerClient(node.regionCode)
228+
229+
try {
230+
const spaceDetails = await client.describeSpace({
231+
DomainId: node.spaceApp.DomainId!,
232+
SpaceName: node.spaceApp.SpaceName!,
233+
})
234+
235+
const appType = spaceDetails.SpaceSettings!.AppType!
236+
237+
// Get current instance type
238+
const currentResourceSpec =
239+
appType === 'JupyterLab'
240+
? spaceDetails.SpaceSettings!.JupyterLabAppSettings?.DefaultResourceSpec
241+
: spaceDetails.SpaceSettings!.CodeEditorAppSettings?.DefaultResourceSpec
242+
243+
const currentInstanceType = currentResourceSpec?.InstanceType
244+
245+
// Check if upgrade is needed
246+
if (currentInstanceType && currentInstanceType in InstanceTypeInsufficientMemory) {
247+
// Current type has insufficient memory
248+
return {
249+
upgradeNeeded: true,
250+
currentType: currentInstanceType,
251+
recommendedType: InstanceTypeInsufficientMemory[currentInstanceType],
211252
}
253+
}
254+
255+
return { upgradeNeeded: false, currentType: currentInstanceType }
256+
} catch (err) {
257+
const error = err as Error
258+
if (error instanceof AccessDeniedException) {
259+
throw new ToolkitError('You do not have permission to describe spaces. Please contact your administrator', {
260+
cause: error,
261+
code: error.name,
262+
})
263+
}
264+
throw err
265+
}
266+
}
267+
268+
/**
269+
* Handles connecting to a running space with disabled remote access
270+
* Requires stopping the space, enabling remote access, and restarting
271+
*/
272+
async function handleRunningSpaceWithDisabledAccess(
273+
node: SagemakerSpaceNode | SagemakerUnifiedStudioSpaceNode,
274+
ctx: vscode.ExtensionContext,
275+
spaceName: string,
276+
sageMakerClient?: SagemakerClient
277+
) {
278+
// Check if instance type upgrade will be needed
279+
const instanceTypeInfo = await checkInstanceTypeUpgradeNeeded(node, sageMakerClient)
280+
281+
let prompt: string
282+
if (instanceTypeInfo.upgradeNeeded) {
283+
prompt = InstanceTypeInsufficientMemoryMessage(
284+
spaceName,
285+
instanceTypeInfo.currentType!,
286+
instanceTypeInfo.recommendedType!
287+
)
288+
} else {
289+
// Only remote access needs to be enabled
290+
prompt = RemoteAccessRequiredMessage
291+
}
292+
293+
const confirmed = await showConfirmationMessage({
294+
prompt,
295+
confirm: 'Restart and Connect',
296+
cancel: 'Cancel',
297+
type: 'warning',
298+
})
299+
300+
if (!confirmed) {
301+
return
302+
}
303+
304+
// Enable remote access and connect
305+
const client = sageMakerClient || new SagemakerClient(node.regionCode)
306+
307+
return await vscode.window.withProgress(
308+
{
309+
location: vscode.ProgressLocation.Notification,
310+
cancellable: false,
311+
title: `Connecting to ${spaceName}`,
312+
},
313+
async (progress) => {
314+
try {
315+
// Show initial progress message
316+
progress.report({ message: 'Stopping the space' })
317+
318+
// Stop the running space
319+
await client.deleteApp({
320+
DomainId: node.spaceApp.DomainId!,
321+
SpaceName: spaceName,
322+
AppType: node.spaceApp.SpaceSettingsSummary!.AppType!,
323+
AppName: node.spaceApp.App?.AppName,
324+
})
212325

213-
// Only start showing progress after instance type validation
214-
return await vscode.window.withProgress(
215-
{
216-
location: vscode.ProgressLocation.Notification,
217-
cancellable: false,
218-
title: `Connecting to ${spaceName}`,
219-
},
220-
async (progress) => {
221-
progress.report({ message: 'Starting the space.' })
222-
await client.waitForAppInService(node.spaceApp.DomainId!, spaceName, appType)
223-
await tryRemoteConnection(node, ctx, progress)
326+
// Update progress message
327+
progress.report({ message: 'Starting the space' })
328+
329+
// Start the space with remote access enabled (skip prompts since user already consented)
330+
await client.startSpace(spaceName, node.spaceApp.DomainId!, true)
331+
await tryRefreshNode(node)
332+
await client.waitForAppInService(
333+
node.spaceApp.DomainId!,
334+
spaceName,
335+
node.spaceApp.SpaceSettingsSummary!.AppType!
336+
)
337+
await tryRemoteConnection(node, ctx, progress)
338+
} catch (err: any) {
339+
// Handle user declining instance type upgrade
340+
if (err.code === InstanceTypeError) {
341+
return
224342
}
225-
)
226-
} catch (err: any) {
227-
// Ignore InstanceTypeError since it means the user decided not to use an instanceType with more memory
228-
// just return without showing progress
229-
if (err.code === InstanceTypeError) {
230-
return
343+
throw new ToolkitError(`Remote connection failed: ${err.message}`, {
344+
cause: err,
345+
code: err.code,
346+
})
231347
}
232-
throw new ToolkitError(`Remote connection failed: ${(err as Error).message}`, {
233-
cause: err as Error,
234-
code: err.code,
235-
})
236348
}
237-
} else if (node.getStatus() === 'Running') {
238-
// For running spaces, show progress
349+
)
350+
}
351+
352+
/**
353+
* Handles connecting to a stopped space
354+
* Starts the space and connects (remote access enabled automatically if needed)
355+
*/
356+
async function handleStoppedSpace(
357+
node: SagemakerSpaceNode | SagemakerUnifiedStudioSpaceNode,
358+
ctx: vscode.ExtensionContext,
359+
spaceName: string,
360+
sageMakerClient?: SagemakerClient
361+
) {
362+
const client = sageMakerClient || new SagemakerClient(node.regionCode)
363+
364+
try {
365+
await client.startSpace(spaceName, node.spaceApp.DomainId!)
366+
await tryRefreshNode(node)
367+
239368
return await vscode.window.withProgress(
240369
{
241370
location: vscode.ProgressLocation.Notification,
242371
cancellable: false,
243372
title: `Connecting to ${spaceName}`,
244373
},
245374
async (progress) => {
375+
progress.report({ message: 'Starting the space' })
376+
await client.waitForAppInService(
377+
node.spaceApp.DomainId!,
378+
spaceName,
379+
node.spaceApp.SpaceSettingsSummary!.AppType!
380+
)
246381
await tryRemoteConnection(node, ctx, progress)
247382
}
248383
)
384+
} catch (err: any) {
385+
// Handle user declining instance type upgrade
386+
if (err.code === InstanceTypeError) {
387+
return
388+
}
389+
throw new ToolkitError(`Remote connection failed: ${(err as Error).message}`, {
390+
cause: err as Error,
391+
code: err.code,
392+
})
249393
}
250394
}
395+
396+
/**
397+
* Handles connecting to a running space with enabled remote access
398+
* Direct connection without any space modifications
399+
*/
400+
async function handleRunningSpaceWithEnabledAccess(
401+
node: SagemakerSpaceNode | SagemakerUnifiedStudioSpaceNode,
402+
ctx: vscode.ExtensionContext,
403+
spaceName: string,
404+
sageMakerClient?: SagemakerClient
405+
) {
406+
return await vscode.window.withProgress(
407+
{
408+
location: vscode.ProgressLocation.Notification,
409+
cancellable: false,
410+
title: `Connecting to ${spaceName}`,
411+
},
412+
async (progress) => {
413+
await tryRemoteConnection(node, ctx, progress)
414+
}
415+
)
416+
}

packages/core/src/awsService/sagemaker/constants.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,19 @@ export const InstanceTypeInsufficientMemory: Record<string, string> = {
1818
'ml.c5.large': 'ml.c5.xlarge',
1919
}
2020

21+
// Remote access constants
22+
export const RemoteAccess = {
23+
ENABLED: 'ENABLED',
24+
DISABLED: 'DISABLED',
25+
} as const
26+
27+
export const SpaceStatus = {
28+
RUNNING: 'Running',
29+
STOPPED: 'Stopped',
30+
STARTING: 'Starting',
31+
STOPPING: 'Stopping',
32+
} as const
33+
2134
export const InstanceTypeInsufficientMemoryMessage = (
2235
spaceName: string,
2336
chosenInstanceType: string,
@@ -29,3 +42,6 @@ export const InstanceTypeInsufficientMemoryMessage = (
2942
export const InstanceTypeNotSelectedMessage = (spaceName: string) => {
3043
return `No instanceType specified for [${spaceName}]. ${InstanceTypeMinimum} is the default instance type, which meets minimum 8 GiB memory requirements for remote access. Continuing will start your space with instanceType [${InstanceTypeMinimum}] and remotely connect.`
3144
}
45+
46+
export const RemoteAccessRequiredMessage =
47+
'This space requires remote access to be enabled.\nWould you like to restart the space and connect?\nAny unsaved work will be lost.'

0 commit comments

Comments
 (0)