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
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import { MynahIcons, Status } from '@aws/mynah-ui'
import { FollowUpTypes, NewFileInfo } from '../shared/types'
import { i18n } from '../shared/i18n'

// For uniquely identifiying which chat messages should be routed to Doc
export const docChat = 'docChat'

export const docScheme = 'aws-doc'

export const featureName = 'Amazon Q Doc Generation'

export function getFileSummaryPercentage(input: string): number {
// Split the input string by newline characters
const lines = input.split('\n')

// Find the line containing "summarized:"
const summaryLine = lines.find(line => line.includes('summarized:'))

// If the line is not found, return null
if (!summaryLine) {
return -1
}

// Extract the numbers from the summary line
const [summarized, total] = summaryLine.split(':')[1].trim().split(' of ').map(Number)

// Calculate the percentage
const percentage = (summarized / total) * 100

return percentage
}

const checkIcons = {
wait: '☐',
current: '☐',
done: '☑',
}

const getIconForStep = (targetStep: number, currentStep: number) => {
return currentStep === targetStep
? checkIcons.current
: currentStep > targetStep
? checkIcons.done
: checkIcons.wait
}

export enum DocGenerationStep {
UPLOAD_TO_S3,
SUMMARIZING_FILES,
GENERATING_ARTIFACTS,
}

export const docGenerationProgressMessage = (currentStep: DocGenerationStep, mode: Mode) => `
${mode === Mode.CREATE ? i18n('AWS.amazonq.doc.answer.creating') : i18n('AWS.amazonq.doc.answer.updating')}

${getIconForStep(DocGenerationStep.UPLOAD_TO_S3, currentStep)} ${i18n('AWS.amazonq.doc.answer.scanning')}

${getIconForStep(DocGenerationStep.SUMMARIZING_FILES, currentStep)} ${i18n('AWS.amazonq.doc.answer.summarizing')}

${getIconForStep(DocGenerationStep.GENERATING_ARTIFACTS, currentStep)} ${i18n('AWS.amazonq.doc.answer.generating')}


`

export const docGenerationSuccessMessage = (mode: Mode) =>
mode === Mode.CREATE ? i18n('AWS.amazonq.doc.answer.readmeCreated') : i18n('AWS.amazonq.doc.answer.readmeUpdated')

export const docRejectConfirmation = 'Your changes have been discarded.'

export const FolderSelectorFollowUps = [
{
icon: 'ok' as MynahIcons,
pillText: 'Yes',
prompt: 'Yes',
status: 'success' as Status,
type: FollowUpTypes.ProceedFolderSelection,
Copy link
Contributor

Choose a reason for hiding this comment

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

Presumably these are going to change, but for now we copied in their dependencies so this can build

},
{
icon: 'refresh' as MynahIcons,
pillText: 'Change folder',
prompt: 'Change folder',
status: 'info' as Status,
type: FollowUpTypes.ChooseFolder,
},
{
icon: 'cancel' as MynahIcons,
pillText: 'Cancel',
prompt: 'Cancel',
status: 'error' as Status,
type: FollowUpTypes.CancelFolderSelection,
},
]

export const CodeChangeFollowUps = [
{
pillText: i18n('AWS.amazonq.doc.pillText.accept'),
prompt: i18n('AWS.amazonq.doc.pillText.accept'),
type: FollowUpTypes.AcceptChanges,
icon: 'ok' as MynahIcons,
status: 'success' as Status,
},
{
pillText: i18n('AWS.amazonq.doc.pillText.makeChanges'),
prompt: i18n('AWS.amazonq.doc.pillText.makeChanges'),
type: FollowUpTypes.MakeChanges,
icon: 'refresh' as MynahIcons,
status: 'info' as Status,
},
{
pillText: i18n('AWS.amazonq.doc.pillText.reject'),
prompt: i18n('AWS.amazonq.doc.pillText.reject'),
type: FollowUpTypes.RejectChanges,
icon: 'cancel' as MynahIcons,
status: 'error' as Status,
},
]

export const NewSessionFollowUps = [
{
pillText: i18n('AWS.amazonq.doc.pillText.newTask'),
type: FollowUpTypes.NewTask,
status: 'info' as Status,
},
{
pillText: i18n('AWS.amazonq.doc.pillText.closeSession'),
type: FollowUpTypes.CloseSession,
status: 'info' as Status,
},
]

export const SynchronizeDocumentation = {
pillText: i18n('AWS.amazonq.doc.pillText.update'),
prompt: i18n('AWS.amazonq.doc.pillText.update'),
type: FollowUpTypes.SynchronizeDocumentation,
}

export const EditDocumentation = {
pillText: i18n('AWS.amazonq.doc.pillText.makeChange'),
prompt: i18n('AWS.amazonq.doc.pillText.makeChange'),
type: FollowUpTypes.EditDocumentation,
}

export enum Mode {
NONE = 'None',
CREATE = 'Create',
SYNC = 'Sync',
EDIT = 'Edit',
}

/**
*
* @param paths file paths
* @returns the path to a README.md, or undefined if none exist
*/
export const findReadmePath = (paths?: NewFileInfo[]) => {
return paths?.find(path => /readme\.md$/i.test(path.relativePath))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

//TODO: extend the toolkit error once ready
// import { ClientError, ContentLengthError as CommonContentLengthError } from '../shared/errors'
import { i18n } from '../shared/i18n'

export class DocClientError {
remainingIterations?: number
constructor(message: string, code: string, remainingIterations?: number) {
// super(message, { code })
this.remainingIterations = remainingIterations
}
}

export class ReadmeTooLargeError extends DocClientError {
constructor() {
super(i18n('AWS.amazonq.doc.error.readmeTooLarge'), ReadmeTooLargeError.name)
}
}

export class ReadmeUpdateTooLargeError extends DocClientError {
constructor(remainingIterations: number) {
super(i18n('AWS.amazonq.doc.error.readmeUpdateTooLarge'), ReadmeUpdateTooLargeError.name, remainingIterations)
}
}

export class WorkspaceEmptyError extends DocClientError {
constructor() {
super(i18n('AWS.amazonq.doc.error.workspaceEmpty'), WorkspaceEmptyError.name)
}
}

export class NoChangeRequiredException extends DocClientError {
constructor() {
super(i18n('AWS.amazonq.doc.error.noChangeRequiredException'), NoChangeRequiredException.name)
}
}

export class PromptRefusalException extends DocClientError {
constructor(remainingIterations: number) {
super(i18n('AWS.amazonq.doc.error.promptRefusal'), PromptRefusalException.name, remainingIterations)
}
}

// TODO: move the common content length error to shared folder
// export class ContentLengthError extends CommonContentLengthError {
// constructor() {
// super(i18n('AWS.amazonq.doc.error.contentLengthError'), { code: ContentLengthError.name })
// }
// }
export class PromptTooVagueError extends DocClientError {
constructor(remainingIterations: number) {
super(i18n('AWS.amazonq.doc.error.promptTooVague'), PromptTooVagueError.name, remainingIterations)
}
}

export class PromptUnrelatedError extends DocClientError {
constructor(remainingIterations: number) {
super(i18n('AWS.amazonq.doc.error.promptUnrelated'), PromptUnrelatedError.name, remainingIterations)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function i18n(text: string): string {
Copy link
Contributor

Choose a reason for hiding this comment

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

this is just a stub because we didn't know what support flare has (or is going to have) for i18n

return text
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import { WorkspaceFolder } from '@aws/language-server-runtimes/protocol'

//TODO: May not be needed follow up with flare
export enum FollowUpTypes {
// UnitTestGeneration
ViewDiff = 'ViewDiff',
AcceptCode = 'AcceptCode',
RejectCode = 'RejectCode',
BuildAndExecute = 'BuildAndExecute',
ModifyCommands = 'ModifyCommands',
SkipBuildAndFinish = 'SkipBuildAndFinish',
InstallDependenciesAndContinue = 'InstallDependenciesAndContinue',
ContinueBuildAndExecute = 'ContinueBuildAndExecute',
ViewCodeDiffAfterIteration = 'ViewCodeDiffAfterIteration',
// FeatureDev
GenerateCode = 'GenerateCode',
InsertCode = 'InsertCode',
ProvideFeedbackAndRegenerateCode = 'ProvideFeedbackAndRegenerateCode',
Retry = 'Retry',
ModifyDefaultSourceFolder = 'ModifyDefaultSourceFolder',
DevExamples = 'DevExamples',
NewTask = 'NewTask',
CloseSession = 'CloseSession',
SendFeedback = 'SendFeedback',
AcceptAutoBuild = 'AcceptAutoBuild',
DenyAutoBuild = 'DenyAutoBuild',
GenerateDevFile = 'GenerateDevFile',
// Doc
CreateDocumentation = 'CreateDocumentation',
ChooseFolder = 'ChooseFolder',
UpdateDocumentation = 'UpdateDocumentation',
SynchronizeDocumentation = 'SynchronizeDocumentation',
EditDocumentation = 'EditDocumentation',
AcceptChanges = 'AcceptChanges',
RejectChanges = 'RejectChanges',
MakeChanges = 'MakeChanges',
ProceedFolderSelection = 'ProceedFolderSelection',
CancelFolderSelection = 'CancelFolderSelection',
}

export type DiffTreeFileInfo = {
zipFilePath: string
relativePath: string
rejected: boolean
changeApplied: boolean
}

export type NewFileZipContents = { zipFilePath: string; fileContent: string }

export type DeletedFileInfo = DiffTreeFileInfo & {
workspaceFolder: WorkspaceFolder
}

export type NewFileInfo = DiffTreeFileInfo &
NewFileZipContents & {
virtualMemoryUri: string
workspaceFolder: WorkspaceFolder
}
Loading