From fbdefdebfd49c1f17c8948766c03fd52a9628290 Mon Sep 17 00:00:00 2001 From: Thomas Ruggeri Date: Tue, 8 Jul 2025 15:38:55 -0700 Subject: [PATCH] feat(appcomposer): Update CFN snippet source --- .../core/src/applicationcomposer/constants.ts | 10 ++ .../generateResourceHandler.ts | 138 ++---------------- .../src/applicationcomposer/webviewManager.ts | 7 +- 3 files changed, 27 insertions(+), 128 deletions(-) create mode 100644 packages/core/src/applicationcomposer/constants.ts diff --git a/packages/core/src/applicationcomposer/constants.ts b/packages/core/src/applicationcomposer/constants.ts new file mode 100644 index 00000000000..1eb3852ad6a --- /dev/null +++ b/packages/core/src/applicationcomposer/constants.ts @@ -0,0 +1,10 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +const isLocalDev = false +const localhost = 'http://127.0.0.1:3000' +const cdn = 'https://ide-toolkits.app-composer.aws.dev' + +export { isLocalDev, localhost, cdn } diff --git a/packages/core/src/applicationcomposer/messageHandlers/generateResourceHandler.ts b/packages/core/src/applicationcomposer/messageHandlers/generateResourceHandler.ts index 6d3e96b81c3..fe31e40ef27 100644 --- a/packages/core/src/applicationcomposer/messageHandlers/generateResourceHandler.ts +++ b/packages/core/src/applicationcomposer/messageHandlers/generateResourceHandler.ts @@ -2,12 +2,6 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -import { - GenerateAssistantResponseRequest, - SupplementaryWebLink, - Reference, - UserIntent, -} from '@amzn/codewhisperer-streaming' import { GenerateResourceRequestMessage, @@ -16,15 +10,13 @@ import { Command, MessageType, } from '../types' -import globals from '../../shared/extensionGlobals' import { getLogger } from '../../shared/logger/logger' -import { AmazonqNotFoundError, getAmazonqApi } from '../../amazonq/extApi' - -const TIMEOUT = 30_000 +import request from '../../shared/request' +import { isLocalDev, localhost, cdn } from '../constants' export async function generateResourceHandler(request: GenerateResourceRequestMessage, context: WebviewContext) { try { - const { chatResponse, references, metadata, isSuccess } = await generateResource(request.cfnType) + const { chatResponse, references, metadata, isSuccess } = await fetchExampleResource(request.cfnType) const responseMessage: GenerateResourceResponseMessage = { command: Command.GENERATE_RESOURCE, @@ -54,116 +46,18 @@ export async function generateResourceHandler(request: GenerateResourceRequestMe } } -async function generateResource(cfnType: string) { - let startTime = globals.clock.Date.now() - +async function fetchExampleResource(cfnType: string) { try { - const amazonqApi = await getAmazonqApi() - if (!amazonqApi) { - throw new AmazonqNotFoundError() - } - const request: GenerateAssistantResponseRequest = { - conversationState: { - currentMessage: { - userInputMessage: { - content: cfnType, - userIntent: UserIntent.GENERATE_CLOUDFORMATION_TEMPLATE, - }, - }, - chatTriggerType: 'MANUAL', - }, - } - - let response = '' - let metadata - let conversationId - let supplementaryWebLinks: SupplementaryWebLink[] = [] - let references: Reference[] = [] - - await amazonqApi.authApi.reauthIfNeeded() - - startTime = globals.clock.Date.now() - // TODO-STARLING - Revisit to see if timeout still needed prior to launch - const data = await timeout(amazonqApi.chatApi.chat(request), TIMEOUT) - const initialResponseTime = globals.clock.Date.now() - startTime - getLogger().debug(`CW Chat initial response: %O, ${initialResponseTime} ms`, data) - if (data['$metadata']) { - metadata = data['$metadata'] - } - - if (data.generateAssistantResponseResponse === undefined) { - getLogger().debug(`Error: Unexpected model response: %O`, data) - throw new Error('No model response') - } - - for await (const value of data.generateAssistantResponseResponse) { - if (value?.assistantResponseEvent?.content) { - try { - response += value.assistantResponseEvent.content - } catch (error: any) { - getLogger().debug(`Warning: Failed to parse content response: ${error.message}`) - throw new Error('Invalid model response') - } - } - if (value?.messageMetadataEvent?.conversationId) { - conversationId = value.messageMetadataEvent.conversationId - } - - const newWebLinks = value?.supplementaryWebLinksEvent?.supplementaryWebLinks - - if (newWebLinks && newWebLinks.length > 0) { - supplementaryWebLinks = supplementaryWebLinks.concat(newWebLinks) - } - - if (value.codeReferenceEvent?.references && value.codeReferenceEvent.references.length > 0) { - references = references.concat(value.codeReferenceEvent.references) - - // Code References are not expected for these single resource prompts - // As we don't yet have the workflows needed to accept references, create the properly structured - // CW Reference log event, we will reject responses that have code references - let errorMessage = 'Code references found for this response, rejecting.' - - if (conversationId) { - errorMessage += ` cID(${conversationId})` - } - - if (metadata?.requestId) { - errorMessage += ` rID(${metadata.requestId})` - } - - throw new Error(errorMessage) - } - } - - const elapsedTime = globals.clock.Date.now() - startTime - - getLogger().debug( - `CW Chat Debug message: - cfnType = "${cfnType}", - conversationId = ${conversationId}, - metadata = %O, - supplementaryWebLinks = %O, - references = %O, - response = "${response}", - initialResponse = ${initialResponseTime} ms, - elapsed time = ${elapsedTime} ms`, - metadata, - supplementaryWebLinks, - references - ) - + const source = isLocalDev ? localhost : cdn + const resp = request.fetch('GET', `${source}/examples/${convertCFNType(cfnType)}.json`, {}) return { - chatResponse: response, + chatResponse: await (await resp.response).text(), references: [], - metadata: { - ...metadata, - conversationId, - queryTime: elapsedTime, - }, + metadata: {}, isSuccess: true, } } catch (error: any) { - getLogger().debug(`CW Chat error: ${error.name} - ${error.message}`) + getLogger().debug(`Resource fetch error: ${error.name} - ${error.message}`) if (error.$metadata) { const { requestId, cfId, extendedRequestId } = error.$metadata getLogger().debug('%O', { requestId, cfId, extendedRequestId }) @@ -173,11 +67,11 @@ async function generateResource(cfnType: string) { } } -function timeout(promise: Promise, ms: number, timeoutError = new Error('Promise timed out')): Promise { - const _timeout = new Promise((_, reject) => { - globals.clock.setTimeout(() => { - reject(timeoutError) - }, ms) - }) - return Promise.race([promise, _timeout]) +function convertCFNType(cfnType: string): string { + const resourceParts = cfnType.split('::') + if (resourceParts.length !== 3) { + throw new Error('CFN type did not contain three parts') + } + + return resourceParts.join('_') } diff --git a/packages/core/src/applicationcomposer/webviewManager.ts b/packages/core/src/applicationcomposer/webviewManager.ts index 884039f907b..92bcbb55593 100644 --- a/packages/core/src/applicationcomposer/webviewManager.ts +++ b/packages/core/src/applicationcomposer/webviewManager.ts @@ -7,16 +7,11 @@ import * as vscode from 'vscode' import * as nls from 'vscode-nls' import request from '../shared/request' import { ApplicationComposer } from './composerWebview' +import { isLocalDev, localhost, cdn } from './constants' import { getLogger } from '../shared/logger/logger' const localize = nls.loadMessageBundle() -// TODO turn this into a flag to make local dev easier -// Change this to true for local dev -const isLocalDev = false -const localhost = 'http://127.0.0.1:3000' -const cdn = 'https://ide-toolkits.app-composer.aws.dev' - const enabledFeatures = ['ide-only', 'anything-resource', 'sfnV2', 'starling'] export class ApplicationComposerManager {