Skip to content

Commit 19af0fd

Browse files
authored
feat(appcomposer): Update CFN snippet source (#7729)
## Problem The AppComposer generate feature is moving from a call to the Q extension to a call to our owned CDN, the same CDN that hosts our webview, or CFN template partials. ## Solution This PR updates the code that used to make a call to the Q extension and instead replaces it with fetch call to the CDN to gather data. Error cases (such as the requested file not being found or the CDN being down) are handled by the existing code. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 841b568 commit 19af0fd

File tree

3 files changed

+27
-128
lines changed

3 files changed

+27
-128
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
const isLocalDev = false
7+
const localhost = 'http://127.0.0.1:3000'
8+
const cdn = 'https://ide-toolkits.app-composer.aws.dev'
9+
10+
export { isLocalDev, localhost, cdn }

packages/core/src/applicationcomposer/messageHandlers/generateResourceHandler.ts

Lines changed: 16 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@
22
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
5-
import {
6-
GenerateAssistantResponseRequest,
7-
SupplementaryWebLink,
8-
Reference,
9-
UserIntent,
10-
} from '@amzn/codewhisperer-streaming'
115

126
import {
137
GenerateResourceRequestMessage,
@@ -16,15 +10,13 @@ import {
1610
Command,
1711
MessageType,
1812
} from '../types'
19-
import globals from '../../shared/extensionGlobals'
2013
import { getLogger } from '../../shared/logger/logger'
21-
import { AmazonqNotFoundError, getAmazonqApi } from '../../amazonq/extApi'
22-
23-
const TIMEOUT = 30_000
14+
import request from '../../shared/request'
15+
import { isLocalDev, localhost, cdn } from '../constants'
2416

2517
export async function generateResourceHandler(request: GenerateResourceRequestMessage, context: WebviewContext) {
2618
try {
27-
const { chatResponse, references, metadata, isSuccess } = await generateResource(request.cfnType)
19+
const { chatResponse, references, metadata, isSuccess } = await fetchExampleResource(request.cfnType)
2820

2921
const responseMessage: GenerateResourceResponseMessage = {
3022
command: Command.GENERATE_RESOURCE,
@@ -54,116 +46,18 @@ export async function generateResourceHandler(request: GenerateResourceRequestMe
5446
}
5547
}
5648

57-
async function generateResource(cfnType: string) {
58-
let startTime = globals.clock.Date.now()
59-
49+
async function fetchExampleResource(cfnType: string) {
6050
try {
61-
const amazonqApi = await getAmazonqApi()
62-
if (!amazonqApi) {
63-
throw new AmazonqNotFoundError()
64-
}
65-
const request: GenerateAssistantResponseRequest = {
66-
conversationState: {
67-
currentMessage: {
68-
userInputMessage: {
69-
content: cfnType,
70-
userIntent: UserIntent.GENERATE_CLOUDFORMATION_TEMPLATE,
71-
},
72-
},
73-
chatTriggerType: 'MANUAL',
74-
},
75-
}
76-
77-
let response = ''
78-
let metadata
79-
let conversationId
80-
let supplementaryWebLinks: SupplementaryWebLink[] = []
81-
let references: Reference[] = []
82-
83-
await amazonqApi.authApi.reauthIfNeeded()
84-
85-
startTime = globals.clock.Date.now()
86-
// TODO-STARLING - Revisit to see if timeout still needed prior to launch
87-
const data = await timeout(amazonqApi.chatApi.chat(request), TIMEOUT)
88-
const initialResponseTime = globals.clock.Date.now() - startTime
89-
getLogger().debug(`CW Chat initial response: %O, ${initialResponseTime} ms`, data)
90-
if (data['$metadata']) {
91-
metadata = data['$metadata']
92-
}
93-
94-
if (data.generateAssistantResponseResponse === undefined) {
95-
getLogger().debug(`Error: Unexpected model response: %O`, data)
96-
throw new Error('No model response')
97-
}
98-
99-
for await (const value of data.generateAssistantResponseResponse) {
100-
if (value?.assistantResponseEvent?.content) {
101-
try {
102-
response += value.assistantResponseEvent.content
103-
} catch (error: any) {
104-
getLogger().debug(`Warning: Failed to parse content response: ${error.message}`)
105-
throw new Error('Invalid model response')
106-
}
107-
}
108-
if (value?.messageMetadataEvent?.conversationId) {
109-
conversationId = value.messageMetadataEvent.conversationId
110-
}
111-
112-
const newWebLinks = value?.supplementaryWebLinksEvent?.supplementaryWebLinks
113-
114-
if (newWebLinks && newWebLinks.length > 0) {
115-
supplementaryWebLinks = supplementaryWebLinks.concat(newWebLinks)
116-
}
117-
118-
if (value.codeReferenceEvent?.references && value.codeReferenceEvent.references.length > 0) {
119-
references = references.concat(value.codeReferenceEvent.references)
120-
121-
// Code References are not expected for these single resource prompts
122-
// As we don't yet have the workflows needed to accept references, create the properly structured
123-
// CW Reference log event, we will reject responses that have code references
124-
let errorMessage = 'Code references found for this response, rejecting.'
125-
126-
if (conversationId) {
127-
errorMessage += ` cID(${conversationId})`
128-
}
129-
130-
if (metadata?.requestId) {
131-
errorMessage += ` rID(${metadata.requestId})`
132-
}
133-
134-
throw new Error(errorMessage)
135-
}
136-
}
137-
138-
const elapsedTime = globals.clock.Date.now() - startTime
139-
140-
getLogger().debug(
141-
`CW Chat Debug message:
142-
cfnType = "${cfnType}",
143-
conversationId = ${conversationId},
144-
metadata = %O,
145-
supplementaryWebLinks = %O,
146-
references = %O,
147-
response = "${response}",
148-
initialResponse = ${initialResponseTime} ms,
149-
elapsed time = ${elapsedTime} ms`,
150-
metadata,
151-
supplementaryWebLinks,
152-
references
153-
)
154-
51+
const source = isLocalDev ? localhost : cdn
52+
const resp = request.fetch('GET', `${source}/examples/${convertCFNType(cfnType)}.json`, {})
15553
return {
156-
chatResponse: response,
54+
chatResponse: await (await resp.response).text(),
15755
references: [],
158-
metadata: {
159-
...metadata,
160-
conversationId,
161-
queryTime: elapsedTime,
162-
},
56+
metadata: {},
16357
isSuccess: true,
16458
}
16559
} catch (error: any) {
166-
getLogger().debug(`CW Chat error: ${error.name} - ${error.message}`)
60+
getLogger().debug(`Resource fetch error: ${error.name} - ${error.message}`)
16761
if (error.$metadata) {
16862
const { requestId, cfId, extendedRequestId } = error.$metadata
16963
getLogger().debug('%O', { requestId, cfId, extendedRequestId })
@@ -173,11 +67,11 @@ async function generateResource(cfnType: string) {
17367
}
17468
}
17569

176-
function timeout<T>(promise: Promise<T>, ms: number, timeoutError = new Error('Promise timed out')): Promise<T> {
177-
const _timeout = new Promise<never>((_, reject) => {
178-
globals.clock.setTimeout(() => {
179-
reject(timeoutError)
180-
}, ms)
181-
})
182-
return Promise.race<T>([promise, _timeout])
70+
function convertCFNType(cfnType: string): string {
71+
const resourceParts = cfnType.split('::')
72+
if (resourceParts.length !== 3) {
73+
throw new Error('CFN type did not contain three parts')
74+
}
75+
76+
return resourceParts.join('_')
18377
}

packages/core/src/applicationcomposer/webviewManager.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,11 @@ import * as vscode from 'vscode'
77
import * as nls from 'vscode-nls'
88
import request from '../shared/request'
99
import { ApplicationComposer } from './composerWebview'
10+
import { isLocalDev, localhost, cdn } from './constants'
1011
import { getLogger } from '../shared/logger/logger'
1112

1213
const localize = nls.loadMessageBundle()
1314

14-
// TODO turn this into a flag to make local dev easier
15-
// Change this to true for local dev
16-
const isLocalDev = false
17-
const localhost = 'http://127.0.0.1:3000'
18-
const cdn = 'https://ide-toolkits.app-composer.aws.dev'
19-
2015
const enabledFeatures = ['ide-only', 'anything-resource', 'sfnV2', 'starling']
2116

2217
export class ApplicationComposerManager {

0 commit comments

Comments
 (0)