"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.uiComponentsTexts = exports.DEFAULT_HELP_PROMPT = exports.createMynahUi = exports.handleChatPrompt = exports.handlePromptInputChange = void 0;
/*!
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */
const chat_client_ui_types_1 = require("@aws/chat-client-ui-types");
const language_server_runtimes_types_1 = require("@aws/language-server-runtimes-types");
const mynah_ui_1 = require("@aws/mynah-ui");
const mcpMynahUi_1 = require("./mcpMynahUi");
const tabFactory_1 = require("./tabs/tabFactory");
const disclaimer_1 = require("./texts/disclaimer");
const withAdapter_1 = require("./withAdapter");
const utils_1 = require("./utils");
const history_1 = require("./features/history");
const pairProgramming_1 = require("./texts/pairProgramming");
const rules_1 = require("./features/rules");
const modelSelection_1 = require("./texts/modelSelection");
const paidTier_1 = require("./texts/paidTier");
const imageVerification_1 = require("./imageVerification");
const ContextPrompt = {
    CreateItemId: 'create-saved-prompt',
    CancelButtonId: 'cancel-create-prompt',
    SubmitButtonId: 'submit-create-prompt',
    PromptNameFieldId: 'prompt-name',
};
const getTabPromptInputValue = (mynahUi, tabId, optionId) => {
    const promptInputOptions = mynahUi.getTabData(tabId)?.getStore()?.promptInputOptions ?? [];
    return promptInputOptions.find(item => item.id === optionId)?.value;
};
const getTabPairProgrammingMode = (mynahUi, tabId) => getTabPromptInputValue(mynahUi, tabId, 'pair-programmer-mode') === 'true';
const getTabModelSelection = (mynahUi, tabId) => getTabPromptInputValue(mynahUi, tabId, 'model-selection');
const handlePromptInputChange = (mynahUi, tabId, optionsValues) => {
    const previousPairProgrammerValue = getTabPairProgrammingMode(mynahUi, tabId);
    const currentPairProgrammerValue = optionsValues['pair-programmer-mode'] === 'true';
    if (currentPairProgrammerValue !== previousPairProgrammerValue) {
        mynahUi.addChatItem(tabId, currentPairProgrammerValue ? pairProgramming_1.pairProgrammingModeOn : pairProgramming_1.pairProgrammingModeOff);
    }
    const previousModelSelectionValue = getTabModelSelection(mynahUi, tabId);
    const currentModelSelectionValue = optionsValues['model-selection'];
    const promptInputOptions = mynahUi.getTabData(tabId).getStore()?.promptInputOptions;
    if (currentModelSelectionValue !== previousModelSelectionValue) {
        const modelSelectionPromptOption = promptInputOptions?.find(({ id }) => id === 'model-selection');
        if (modelSelectionPromptOption && modelSelectionPromptOption.type === 'select') {
            const selectedModelName = modelSelectionPromptOption.options?.find(({ value }) => value === currentModelSelectionValue)?.label;
            mynahUi.addChatItem(tabId, (0, modelSelection_1.getModelSelectionChatItem)(selectedModelName ?? currentModelSelectionValue));
        }
    }
    const updatedPromptInputOptions = promptInputOptions?.map(option => {
        option.value = optionsValues[option.id];
        return option;
    });
    mynahUi.updateStore(tabId, {
        promptInputOptions: updatedPromptInputOptions,
    });
    // Store the updated values in tab defaults for new tabs
    mynahUi.updateTabDefaults({
        store: {
            promptInputOptions: updatedPromptInputOptions,
        },
    });
};
exports.handlePromptInputChange = handlePromptInputChange;
const handleChatPrompt = (mynahUi, tabId, prompt, messager, triggerType, _eventId, agenticMode, tabFactory) => {
    let userPrompt = prompt.escapedPrompt;
    // Check if there's an ongoing request
    const isLoading = mynahUi.getTabData(tabId)?.getStore()?.loadingChat;
    if (isLoading) {
        // Stop the current response
        messager.onStopChatResponse(tabId);
        // Add cancellation message BEFORE showing the new prompt
        mynahUi.addChatItem(tabId, {
            type: mynah_ui_1.ChatItemType.DIRECTIVE,
            messageId: 'stopped' + Date.now(),
            body: 'You stopped your current work and asked me to work on the following task instead.',
        });
        // Reset loading state
        mynahUi.updateStore(tabId, {
            loadingChat: false,
            cancelButtonWhenLoading: true,
            promptInputDisabledState: false,
        });
    }
    else {
        // If no ongoing request, just send the stop signal
        messager.onStopChatResponse(tabId);
    }
    const commandsToReroute = ['/dev', '/test', '/doc', '/review'];
    const isReroutedCommand = agenticMode && tabFactory?.isRerouteEnabled() && prompt.command && commandsToReroute.includes(prompt.command);
    if (prompt.command && !isReroutedCommand && prompt.command !== '/compact') {
        // Send /compact quick action as normal regular chat prompt
        // Handle non-rerouted commands (/clear, /help, /transform, /review) as quick actions
        // Temporary solution to handle clear quick actions on the client side
        if (prompt.command === '/clear') {
            mynahUi.updateStore(tabId, {
                chatItems: [],
            });
        }
        else if (prompt.command === '/help') {
            userPrompt = exports.DEFAULT_HELP_PROMPT;
        }
        // Send prompt when quick action command attached
        messager.onQuickActionCommand({
            quickAction: prompt.command,
            prompt: userPrompt,
            tabId,
        });
        if (prompt.command === '/clear') {
            return;
        }
    }
    else {
        // Go agentic chat workflow when:
        // 1. Regular prompts without commands
        // 2. Rerouted commands (/dev, /test, /doc, /review) when feature flag: reroute is enabled
        // Special handling for /doc command - always send fixed prompt for fixed response
        if (isReroutedCommand && prompt.command === '/doc') {
            const context = prompt.context?.map(c => (typeof c === 'string' ? { command: c } : c));
            messager.onChatPrompt({
                prompt: { ...prompt, escapedPrompt: DEFAULT_DOC_PROMPT, prompt: DEFAULT_DOC_PROMPT },
                tabId,
                context,
            }, triggerType);
        }
        else if (isReroutedCommand && (!userPrompt || userPrompt.trim() === '')) {
            // For /dev and /test commands, provide meaningful defaults if no additional text
            let defaultPrompt = userPrompt;
            switch (prompt.command) {
                case '/dev':
                    defaultPrompt = DEFAULT_DEV_PROMPT;
                    break;
                case '/test':
                    defaultPrompt = DEFAULT_TEST_PROMPT;
                    break;
                case '/doc':
                    defaultPrompt = DEFAULT_DOC_PROMPT;
                    break;
                case '/review':
                    defaultPrompt = DEFAULT_REVIEW_PROMPT;
                    break;
            }
            // Send the updated prompt with default text to server
            const context = prompt.context?.map(c => (typeof c === 'string' ? { command: c } : c));
            messager.onChatPrompt({
                prompt: { ...prompt, escapedPrompt: defaultPrompt, prompt: defaultPrompt },
                tabId,
                context,
            }, triggerType);
        }
        else {
            const context = prompt.context?.map(c => (typeof c === 'string' ? { command: c } : c));
            messager.onChatPrompt({ prompt, tabId, context }, triggerType);
        }
    }
    // For /doc command, don't show any prompt in UI
    const displayPrompt = isReroutedCommand && prompt.command === '/doc' ? '' : userPrompt;
    initializeChatResponse(mynahUi, tabId, displayPrompt, agenticMode);
};
exports.handleChatPrompt = handleChatPrompt;
const initializeChatResponse = (mynahUi, tabId, userPrompt, agenticMode) => {
    mynahUi.addChatItem(tabId, {
        type: mynah_ui_1.ChatItemType.PROMPT,
        body: userPrompt,
    });
    // Set UI to loading state
    if (agenticMode) {
        mynahUi.updateStore(tabId, {
            loadingChat: true,
            cancelButtonWhenLoading: true,
            promptInputDisabledState: false,
        });
    }
    else {
        mynahUi.updateStore(tabId, {
            loadingChat: true,
            promptInputDisabledState: true,
        });
    }
    // Create initial empty response
    mynahUi.addChatItem(tabId, {
        type: mynah_ui_1.ChatItemType.ANSWER_STREAM,
    });
};
const createMynahUi = (messager, tabFactory, disclaimerAcknowledged, pairProgrammingCardAcknowledged, customChatClientAdapter, featureConfig, agenticMode, stringOverrides, os) => {
    let disclaimerCardActive = !disclaimerAcknowledged;
    let programmingModeCardActive = !pairProgrammingCardAcknowledged;
    let contextCommandGroups;
    let chatEventHandlers = {
        onCodeInsertToCursorPosition(tabId, messageId, code, type, referenceTrackerInformation, eventId, codeBlockIndex, totalCodeBlocks) {
            const payload = {
                tabId,
                messageId,
                code,
                type,
                referenceTrackerInformation,
                eventId,
                codeBlockIndex,
                totalCodeBlocks,
            };
            messager.onInsertToCursorPosition(payload);
        },
        onFocusStateChanged(focusState) {
            messager.onFocusStateChanged(focusState);
        },
        onFollowUpClicked(tabId, messageId, followUp, eventId) {
            if (followUp.type !== undefined && (0, chat_client_ui_types_1.isValidAuthFollowUpType)(followUp.type)) {
                const payload = {
                    tabId,
                    messageId,
                    authFollowupType: followUp.type,
                };
                messager.onAuthFollowUpClicked(payload);
                mynahUi.updateStore(tabId, { promptInputDisabledState: false });
            }
            else {
                const prompt = followUp.prompt ? followUp.prompt : followUp.pillText;
                (0, exports.handleChatPrompt)(mynahUi, tabId, { prompt: prompt, escapedPrompt: prompt }, messager, 'click', eventId, agenticMode, tabFactory);
                const payload = {
                    tabId,
                    messageId,
                    followUp,
                };
                messager.onFollowUpClicked(payload);
            }
        },
        onChatPrompt(tabId, prompt, eventId) {
            (0, exports.handleChatPrompt)(mynahUi, tabId, prompt, messager, 'click', eventId, agenticMode, tabFactory);
        },
        onReady: () => {
            messager.onUiReady();
            messager.onTabAdd(tabFactory.initialTabId);
            messager.onListAvailableModels({ tabId: tabFactory.initialTabId });
        },
        onFileClick: (tabId, filePath, deleted, messageId, eventId, fileDetails) => {
            messager.onFileClick({ tabId, filePath, messageId, fullPath: fileDetails?.data?.['fullPath'] });
        },
        onTabAdd: (tabId) => {
            const defaultTabBarData = tabFactory.getDefaultTabData();
            const defaultTabConfig = {
                quickActionCommands: defaultTabBarData.quickActionCommands,
                tabBarButtons: defaultTabBarData.tabBarButtons,
                contextCommands: [
                    ...(contextCommandGroups || []),
                    ...(featureConfig?.get('highlightCommand')
                        ? [
                            {
                                groupName: 'Additional commands',
                                commands: [(0, utils_1.toMynahContextCommand)(featureConfig.get('highlightCommand'))],
                            },
                        ]
                        : []),
                ],
                ...(disclaimerCardActive ? { promptInputStickyCard: disclaimer_1.disclaimerCard } : {}),
            };
            const tabStore = mynahUi.getTabData(tabId).getStore();
            const storedPromptInputOptions = mynahUi.getTabDefaults().store?.promptInputOptions;
            // Retrieve stored model selection and pair programming mode from defaults
            if (storedPromptInputOptions) {
                defaultTabConfig.promptInputOptions = storedPromptInputOptions;
            }
            // Tabs can be opened through different methods, including server-initiated 'openTab' requests.
            // The 'openTab' request is specifically used for loading historical chat sessions with pre-existing messages.
            // We check if tabMetadata.openTabKey exists - if it does and is set to true, we skip showing welcome messages
            // since this indicates we're loading a previous chat session rather than starting a new one.
            if (!tabStore?.tabMetadata || !tabStore.tabMetadata.openTabKey) {
                defaultTabConfig.chatItems = tabFactory.getChatItems(true, programmingModeCardActive, []);
            }
            mynahUi.updateStore(tabId, defaultTabConfig);
            messager.onTabAdd(tabId, undefined, tabStore?.tabMetadata?.openTabKey === true);
            messager.onListAvailableModels({ tabId });
        },
        onTabRemove: (tabId) => {
            messager.onStopChatResponse(tabId);
            messager.onTabRemove(tabId);
        },
        onTabChange: (tabId) => {
            messager.onTabChange(tabId);
        },
        onResetStore: () => { },
        onCopyCodeToClipboard: (tabId, messageId, code, type, referenceTrackerInformation, eventId, codeBlockIndex, totalCodeBlocks) => {
            const payload = {
                tabId,
                messageId,
                code,
                type,
                referenceTrackerInformation,
                eventId,
                codeBlockIndex,
                totalCodeBlocks,
            };
            messager.onCopyCodeToClipboard(payload);
        },
        onVote: (tabId, messageId, vote, eventId) => {
            const payload = {
                tabId,
                messageId,
                vote,
                eventId,
            };
            messager.onVote(payload);
        },
        onPromptTopBarItemAdded: (tabId, item, eventId) => {
            messager.onAddPinnedContext({ tabId, contextCommandGroups: [{ commands: [item] }] });
        },
        onPromptTopBarItemRemoved: (tabId, item, eventId) => {
            messager.onRemovePinnedContext({ tabId, contextCommandGroups: [{ commands: [item] }] });
        },
        onPromptTopBarButtonClick(tabId, button, eventId) {
            if (button.id === 'Rules') {
                rulesList.showLoading(tabId);
                messager.onListRules({ tabId });
            }
        },
        onSendFeedback: (tabId, feedbackPayload, eventId) => {
            const payload = {
                tabId,
                feedbackPayload,
                eventId,
            };
            messager.onSendFeedback(payload);
            mynahUi.notify({
                type: mynah_ui_1.NotificationType.INFO,
                title: 'Your feedback is sent',
                content: 'Thanks for your feedback.',
            });
        },
        onLinkClick: (tabId, messageId, link, mouseEvent, eventId) => {
            mouseEvent?.preventDefault();
            mouseEvent?.stopPropagation();
            mouseEvent?.stopImmediatePropagation();
            const payload = {
                tabId,
                messageId,
                link,
                eventId,
            };
            messager.onLinkClick(payload);
        },
        onSourceLinkClick: (tabId, messageId, link, mouseEvent, eventId) => {
            mouseEvent?.preventDefault();
            mouseEvent?.stopPropagation();
            mouseEvent?.stopImmediatePropagation();
            const payload = {
                tabId,
                messageId,
                link,
                eventId,
            };
            messager.onSourceLinkClick(payload);
        },
        onInfoLinkClick: (tabId, link, mouseEvent, eventId) => {
            mouseEvent?.preventDefault();
            mouseEvent?.stopPropagation();
            mouseEvent?.stopImmediatePropagation();
            const payload = {
                tabId,
                link,
                eventId,
            };
            messager.onInfoLinkClick(payload);
        },
        onInBodyButtonClicked: (tabId, messageId, action, eventId) => {
            if (action.id === disclaimer_1.disclaimerAcknowledgeButtonId) {
                // Hide the legal disclaimer card
                disclaimerCardActive = false;
                // Update the disclaimer getting acknowledged
                messager.onDisclaimerAcknowledged();
                // Remove all disclaimer cards from all tabs
                Object.keys(mynahUi.getAllTabs()).forEach(storeTabKey => {
                    mynahUi.updateStore(storeTabKey, { promptInputStickyCard: null });
                });
            }
            else if (action.id === language_server_runtimes_types_1.OPEN_WORKSPACE_INDEX_SETTINGS_BUTTON_ID) {
                messager.onOpenSettings('amazonQ.workspaceIndex');
            }
            else {
                const payload = {
                    tabId,
                    messageId,
                    buttonId: action.id,
                };
                messager.onButtonClick(payload);
            }
            if (action.id === 'stop-shell-command') {
                messager.onStopChatResponse(tabId);
            }
        },
        onContextSelected: (contextItem, tabId) => {
            if (contextItem.command === 'Image') {
                const imageContext = getImageContextCount(tabId);
                if (imageContext >= imageVerification_1.MAX_IMAGE_CONTEXT) {
                    mynahUi.notify({
                        content: `A maximum of ${imageVerification_1.MAX_IMAGE_CONTEXT} images can be added to a single message.`,
                        type: mynah_ui_1.NotificationType.WARNING,
                    });
                    return false;
                }
                const payload = {
                    tabId,
                    fileType: contextItem.command.toLowerCase(),
                };
                messager.onOpenFileDialogClick(payload);
                return false;
            }
            if (contextItem.id === ContextPrompt.CreateItemId) {
                mynahUi.showCustomForm(tabId, [
                    {
                        id: ContextPrompt.PromptNameFieldId,
                        type: 'textinput',
                        mandatory: true,
                        autoFocus: true,
                        title: 'Prompt name',
                        placeholder: 'Enter prompt name',
                        validationPatterns: {
                            patterns: [
                                {
                                    pattern: /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,99}$/,
                                    errorMessage: 'Use only letters, numbers, hyphens, and underscores, starting with a letter or number. Maximum 100 characters.',
                                },
                            ],
                        },
                        validateOnChange: true,
                        description: "Use this prompt by typing '@' followed by the prompt name.",
                    },
                ], [
                    {
                        id: ContextPrompt.CancelButtonId,
                        text: 'Cancel',
                        status: 'clear',
                        waitMandatoryFormItems: false,
                    },
                    {
                        id: ContextPrompt.SubmitButtonId,
                        text: 'Create',
                        status: 'primary',
                        waitMandatoryFormItems: true,
                    },
                ], `Create a saved prompt`);
                return false;
            }
            return true;
        },
        onCustomFormAction: (tabId, action) => {
            if (action.id === ContextPrompt.SubmitButtonId) {
                messager.onCreatePrompt({ promptName: action.formItemValues[ContextPrompt.PromptNameFieldId] });
            }
            else if (action.id === rules_1.ContextRule.SubmitButtonId) {
                messager.onCreatePrompt({
                    promptName: action.formItemValues[rules_1.ContextRule.RuleNameFieldId],
                    isRule: true,
                });
            }
        },
        onFormTextualItemKeyPress: (event, formData, itemId, _tabId, _eventId) => {
            if (event.key === 'Enter') {
                if (itemId === ContextPrompt.PromptNameFieldId) {
                    event.preventDefault();
                    messager.onCreatePrompt({ promptName: formData[ContextPrompt.PromptNameFieldId] });
                    return true;
                }
                else if (itemId === rules_1.ContextRule.RuleNameFieldId) {
                    event.preventDefault();
                    messager.onCreatePrompt({ promptName: formData[rules_1.ContextRule.RuleNameFieldId], isRule: true });
                    return true;
                }
            }
            return false;
        },
        onTabBarButtonClick: (tabId, buttonId) => {
            if (buttonId === tabFactory_1.McpServerTabButtonId) {
                messager.onListMcpServers();
                return;
            }
            if (buttonId === history_1.ChatHistory.TabBarButtonId) {
                messager.onListConversations(undefined, true);
                return;
            }
            if (buttonId === tabFactory_1.ShowLogsTabBarButtonId) {
                messager.onTabBarAction({
                    tabId,
                    action: 'show_logs',
                });
                return;
            }
            if (buttonId === tabFactory_1.ExportTabBarButtonId) {
                messager.onTabBarAction({
                    tabId,
                    action: 'export',
                });
                return;
            }
            throw new Error(`Unhandled tab bar button id: ${buttonId}`);
        },
        onPromptInputOptionChange: (tabId, optionsValues) => {
            if (agenticMode) {
                (0, exports.handlePromptInputChange)(mynahUi, tabId, optionsValues);
            }
            messager.onPromptInputOptionChange({ tabId, optionsValues });
        },
        onPromptInputButtonClick: (tabId, buttonId, eventId) => {
            const payload = {
                tabId,
                messageId: 'not-a-message',
                buttonId: buttonId,
            };
            messager.onPromptInputButtonClick(payload);
        },
        onMessageDismiss: (tabId, messageId) => {
            if (messageId === pairProgramming_1.programmerModeCard.messageId) {
                programmingModeCardActive = false;
                messager.onChatPromptOptionAcknowledged(messageId);
                // Update the tab defaults to hide the programmer mode card for new tabs
                mynahUi.updateTabDefaults({
                    store: {
                        chatItems: tabFactory.getChatItems(true, false),
                    },
                });
            }
        },
        onStopChatResponse: tabId => {
            handleUIStopChatResponse(messager, mynahUi, tabId);
        },
        onOpenFileDialogClick: (tabId, fileType, insertPosition) => {
            const imageContext = getImageContextCount(tabId);
            if (imageContext >= imageVerification_1.MAX_IMAGE_CONTEXT) {
                mynahUi.notify({
                    content: `A maximum of ${imageVerification_1.MAX_IMAGE_CONTEXT} images can be added to a single message.`,
                    type: mynah_ui_1.NotificationType.WARNING,
                });
                return;
            }
            const payload = {
                tabId,
                fileType: fileType,
                insertPosition,
            };
            messager.onOpenFileDialogClick(payload);
        },
        onFilesDropped: async (tabId, files, insertPosition) => {
            const imageContextCount = getImageContextCount(tabId);
            if (imageContextCount >= imageVerification_1.MAX_IMAGE_CONTEXT) {
                mynahUi.notify({
                    content: `A maximum of ${imageVerification_1.MAX_IMAGE_CONTEXT} images can be added to a single message.`,
                    type: mynah_ui_1.NotificationType.WARNING,
                });
                return;
            }
            // Verify dropped files and add valid ones to context
            const { validFiles, errors } = await (0, imageVerification_1.verifyClientImages)(files);
            if (validFiles.length > 0) {
                // Calculate how many files we can actually add
                const availableSlots = imageVerification_1.MAX_IMAGE_CONTEXT - imageContextCount;
                const filesToAdd = validFiles.slice(0, availableSlots);
                const filesExceeded = validFiles.length - availableSlots;
                // Add error message if we exceed the limit
                if (filesExceeded > 0) {
                    errors.push(`A maximum of ${imageVerification_1.MAX_IMAGE_CONTEXT} images can be added to a single message.`);
                }
                const commands = await Promise.all(filesToAdd.map(async (file) => {
                    const fileName = file.name || 'Unknown file';
                    const filePath = file.name || '';
                    // Determine file type and appropriate icon
                    const fileExtension = filePath.split('.').pop()?.toLowerCase() || '';
                    const isImage = (0, imageVerification_1.isSupportedImageExtension)(fileExtension);
                    let icon = mynah_ui_1.MynahIcons.FILE;
                    if (isImage) {
                        icon = mynah_ui_1.MynahIcons.IMAGE;
                    }
                    const arrayBuffer = await file.arrayBuffer();
                    const bytes = new Uint8Array(arrayBuffer);
                    return {
                        command: fileName,
                        description: filePath,
                        route: [filePath],
                        label: 'image',
                        icon: icon,
                        content: bytes,
                        id: fileName,
                    };
                }));
                // Add valid files to context commands
                mynahUi.addCustomContextToPrompt(tabId, commands, insertPosition);
            }
            if (errors.length > 0) {
                const imageVerificationBanner = {
                    messageId: 'image-verification-banner',
                    header: {
                        icon: 'warning',
                        iconStatus: 'warning',
                        body: '### Invalid Image',
                    },
                    body: `${errors.join('\n')}`,
                    canBeDismissed: true,
                };
                mynahUi.updateStore(tabId, {
                    promptInputStickyCard: imageVerificationBanner,
                });
            }
        },
    };
    const mynahUiProps = {
        tabs: {
            [tabFactory.initialTabId]: {
                isSelected: true,
                store: {
                    ...tabFactory.createTab(disclaimerCardActive),
                    chatItems: tabFactory.getChatItems(true, programmingModeCardActive),
                },
            },
        },
        defaults: {
            store: tabFactory.createTab(false),
        },
        config: {
            maxTabs: 10,
            test: true,
            dragOverlayIcon: mynah_ui_1.MynahIcons.IMAGE,
            texts: {
                ...exports.uiComponentsTexts,
                dragOverlayText: 'Add image to context',
                // Fallback to original texts in non-agentic chat mode
                stopGenerating: agenticMode ? exports.uiComponentsTexts.stopGenerating : 'Stop generating',
                stopGeneratingTooltip: getStopGeneratingToolTipText(os, agenticMode),
                spinnerText: agenticMode ? exports.uiComponentsTexts.spinnerText : 'Generating your answer...',
                ...stringOverrides,
            },
            // Total model context window limit 600k.
            // 500k for user input, 100k for context, history, system prompt.
            // beside, MynahUI will automatically crop it depending on the available chars left from the prompt field itself by using a 96 chars of threshold
            // if we want to max user input as 500000, need to configure the maxUserInput as 500096
            maxUserInput: 500096,
            userInputLengthWarningThreshold: 450000,
            disableTypewriterAnimation: true,
        },
    };
    const mynahUiRef = { mynahUI: undefined };
    if (customChatClientAdapter) {
        // Attach routing to custom adapter top of default message handlers
        chatEventHandlers = (0, withAdapter_1.withAdapter)(chatEventHandlers, mynahUiRef, customChatClientAdapter, tabFactory);
    }
    const mynahUi = new mynah_ui_1.MynahUI({
        ...mynahUiProps,
        ...chatEventHandlers,
    });
    mynahUiRef.mynahUI = mynahUi;
    const getTabStore = (tabId = mynahUi.getSelectedTabId()) => {
        return tabId ? mynahUi.getAllTabs()[tabId]?.store : undefined;
    };
    // The 'openTab' parameter indicates whether this tab creation is initiated by 'openTab' server request
    // to restore a previous chat session (true) or if it's a new client-side tab creation (false/undefined).
    // This distinction helps maintain consistent tab behavior between fresh conversations and restored sessions.
    const createTabId = (openTab) => {
        const tabId = mynahUi.updateStore('', {
            ...tabFactory.createTab(disclaimerCardActive),
            tabMetadata: { openTabKey: openTab ? true : false },
        });
        if (tabId === undefined) {
            mynahUi.notify({
                content: exports.uiComponentsTexts.noMoreTabsTooltip,
                type: mynah_ui_1.NotificationType.WARNING,
            });
            return undefined;
        }
        return tabId;
    };
    const getOrCreateTabId = () => {
        const tabId = mynahUi.getSelectedTabId();
        return tabId ?? createTabId();
    };
    const contextListToHeader = (contextList) => {
        if (contextList === undefined) {
            return undefined;
        }
        return {
            fileList: {
                fileTreeTitle: '',
                filePaths: contextList.filePaths?.map(file => file),
                rootFolderTitle: contextList.rootFolderTitle ?? 'Context',
                flatList: true,
                collapsed: true,
                hideFileCount: true,
                details: Object.fromEntries(Object.entries(contextList.details || {}).map(([filePath, fileDetails]) => [
                    filePath,
                    {
                        label: fileDetails.lineRanges
                            ?.map(range => range.first === -1 || range.second === -1
                            ? ''
                            : `line ${range.first} - ${range.second}`)
                            .join(', ') || '',
                        description: fileDetails.description,
                        clickable: true,
                        data: {
                            fullPath: fileDetails.fullPath || '',
                        },
                    },
                ])),
            },
        };
    };
    const getImageContextCount = (tabId) => {
        const imageContextInPrompt = mynahUi
            .getTabData(tabId)
            ?.getStore()
            ?.customContextCommand?.filter(cm => cm.label === 'image').length || 0;
        const imageContextInPin = mynahUi
            .getTabData(tabId)
            ?.getStore()
            ?.promptTopBarContextItems?.filter(cm => cm.label === 'image').length || 0;
        return imageContextInPrompt + imageContextInPin;
    };
    const addChatResponse = (chatResult, tabId, isPartialResult) => {
        if (agenticMode) {
            agenticAddChatResponse(chatResult, tabId, isPartialResult);
        }
        else {
            legacyAddChatResponse(chatResult, tabId, isPartialResult);
        }
    };
    // addChatResponse handler to support Agentic chat UX changes for handling responses streaming.
    const agenticAddChatResponse = (chatResult, tabId, isPartialResult) => {
        const { type, summary, ...chatResultWithoutTypeSummary } = chatResult;
        let header = (0, utils_1.toMynahHeader)(chatResult.header);
        const fileList = (0, utils_1.toMynahFileList)(chatResult.fileList);
        const buttons = (0, utils_1.toMynahButtons)(chatResult.buttons);
        if (chatResult.contextList !== undefined) {
            header = contextListToHeader(chatResult.contextList);
        }
        const store = mynahUi.getTabData(tabId)?.getStore() || {};
        const chatItems = store.chatItems || [];
        const isPairProgrammingMode = getTabPairProgrammingMode(mynahUi, tabId);
        if (chatResult.additionalMessages?.length) {
            mynahUi.updateStore(tabId, {
                loadingChat: true,
                cancelButtonWhenLoading: true,
            });
            chatResult.additionalMessages.forEach(am => {
                const chatItem = {
                    messageId: am.messageId,
                    type: am.type === 'tool'
                        ? mynah_ui_1.ChatItemType.ANSWER
                        : am.type === 'directive'
                            ? mynah_ui_1.ChatItemType.DIRECTIVE
                            : mynah_ui_1.ChatItemType.ANSWER_STREAM,
                    ...prepareChatItemFromMessage(am, isPairProgrammingMode, isPartialResult),
                };
                if (!chatItems.find(ci => ci.messageId === am.messageId)) {
                    mynahUi.addChatItem(tabId, chatItem);
                }
                else {
                    mynahUi.updateChatAnswerWithMessageId(tabId, am.messageId, chatItem);
                }
            });
        }
        if (isPartialResult) {
            mynahUi.updateStore(tabId, {
                loadingChat: true,
                cancelButtonWhenLoading: true,
            });
            const chatItem = {
                ...chatResultWithoutTypeSummary,
                body: chatResult.body,
                type: mynah_ui_1.ChatItemType.ANSWER_STREAM,
                header: header,
                buttons: buttons,
                fileList,
                codeBlockActions: isPairProgrammingMode ? { 'insert-to-cursor': null } : undefined,
            };
            if (!chatItems.find(ci => ci.messageId === chatResult.messageId)) {
                mynahUi.addChatItem(tabId, chatItem);
            }
            else {
                mynahUi.updateChatAnswerWithMessageId(tabId, chatResult.messageId, chatItem);
            }
            return;
        }
        // If chat response from server is an empty object don't do anything
        if (Object.keys(chatResult).length === 0) {
            return;
        }
        // If the response is auth follow-up show it as a system prompt
        const followUpOptions = chatResult.followUp?.options;
        const isValidAuthFollowUp = followUpOptions &&
            followUpOptions.length > 0 &&
            followUpOptions[0].type &&
            (0, chat_client_ui_types_1.isValidAuthFollowUpType)(followUpOptions[0].type);
        if (chatResult.body === '' && isValidAuthFollowUp) {
            mynahUi.addChatItem(tabId, {
                ...chatResultWithoutTypeSummary,
                header: header,
                buttons: buttons,
                type: mynah_ui_1.ChatItemType.SYSTEM_PROMPT,
            });
            // TODO, prompt should be disabled until user is authenticated
            // Currently we don't have a mechanism to notify chat-client about auth changes
            // mynahUi.updateStore(tabId, { promptInputDisabledState: true })
            return;
        }
        const followUps = chatResult.followUp
            ? {
                text: chatResult.followUp.text ?? 'Suggested follow up questions:',
                options: chatResult.followUp.options,
            }
            : {};
        const chatItem = {
            ...chatResultWithoutTypeSummary,
            body: chatResult.body,
            type: mynah_ui_1.ChatItemType.ANSWER_STREAM,
            header: header,
            buttons: buttons,
            codeBlockActions: isPairProgrammingMode ? { 'insert-to-cursor': null } : undefined,
        };
        if (!chatItems.find(ci => ci.messageId === chatResult.messageId)) {
            mynahUi.addChatItem(tabId, chatItem);
        }
        mynahUi.endMessageStream(tabId, chatResult.messageId ?? '', {
            header: header,
            buttons: buttons,
            body: chatResult.body,
            followUp: followUps,
            relatedContent: chatResult.relatedContent,
            canBeVoted: chatResult.canBeVoted,
            codeReference: chatResult.codeReference,
            fileList: chatResult.fileList,
            // messageId excluded
        });
        mynahUi.updateStore(tabId, {
            loadingChat: false,
            cancelButtonWhenLoading: true,
            promptInputDisabledState: false,
        });
    };
    // addChatResponse handler to support extensions that haven't migrated to agentic chat yet
    const legacyAddChatResponse = (chatResult, tabId, isPartialResult) => {
        const { type, summary, ...chatResultWithoutTypeSummary } = chatResult;
        let header = undefined;
        if (chatResult.contextList !== undefined) {
            header = {
                fileList: {
                    fileTreeTitle: '',
                    filePaths: chatResult.contextList.filePaths?.map(file => file),
                    rootFolderTitle: 'Context',
                    flatList: true,
                    collapsed: true,
                    hideFileCount: true,
                    details: Object.fromEntries(Object.entries(chatResult.contextList.details || {}).map(([filePath, fileDetails]) => [
                        filePath,
                        {
                            label: fileDetails.lineRanges
                                ?.map(range => range.first === -1 || range.second === -1
                                ? ''
                                : `line ${range.first} - ${range.second}`)
                                .join(', ') || '',
                            description: filePath,
                            clickable: true,
                        },
                    ])),
                },
            };
        }
        if (isPartialResult) {
            // @ts-expect-error - type for MynahUI differs from ChatResult types so we ignore it
            mynahUi.updateLastChatAnswer(tabId, { ...chatResultWithoutTypeSummary, header: header });
            return;
        }
        // If chat response from server is an empty object don't do anything
        if (Object.keys(chatResult).length === 0) {
            return;
        }
        // If the response is auth follow-up show it as a system prompt
        const followUpOptions = chatResult.followUp?.options;
        const isValidAuthFollowUp = followUpOptions &&
            followUpOptions.length > 0 &&
            followUpOptions[0].type &&
            (0, chat_client_ui_types_1.isValidAuthFollowUpType)(followUpOptions[0].type);
        if (chatResult.body === '' && isValidAuthFollowUp) {
            // @ts-expect-error - type for MynahUI differs from ChatResult types so we ignore it
            mynahUi.addChatItem(tabId, {
                type: mynah_ui_1.ChatItemType.SYSTEM_PROMPT,
                ...chatResultWithoutTypeSummary,
            });
            // TODO, prompt should be disabled until user is authenticated
            // Currently we don't have a mechanism to notify chat-client about auth changes
            // mynahUi.updateStore(tabId, { promptInputDisabledState: true })
            return;
        }
        const followUps = chatResult.followUp
            ? {
                text: chatResult.followUp.text ?? 'Suggested follow up questions:',
                options: chatResult.followUp.options,
            }
            : {};
        mynahUi.updateLastChatAnswer(tabId, {
            header: header,
            body: chatResult.body,
            messageId: chatResult.messageId,
            followUp: followUps,
            relatedContent: chatResult.relatedContent,
            canBeVoted: chatResult.canBeVoted,
        });
        mynahUi.endMessageStream(tabId, chatResult.messageId ?? '');
        mynahUi.updateStore(tabId, {
            loadingChat: false,
            promptInputDisabledState: false,
        });
    };
    /**
     * Adjusts the UI when the user changes to/from free-tier/paid-tier.
     * Shows a message if the user reaches free-tier limit.
     * Shows a message if the user just upgraded to paid-tier.
     */
    const onPaidTierModeChange = (tabId, mode) => {
        if (!mode || !['freetier', 'freetier-limit', 'upgrade-pending', 'paidtier'].includes(mode)) {
            return false; // invalid mode
        }
        tabId = tabId ? tabId : getOrCreateTabId();
        const store = mynahUi.getTabData(tabId).getStore() || {};
        // Detect if the tab is already showing the "Upgrade Q" UI.
        const isFreeTierLimitUi = store.promptInputStickyCard?.messageId === paidTier_1.freeTierLimitSticky.messageId;
        const isUpgradePendingUi = store.promptInputStickyCard?.messageId === paidTier_1.upgradePendingSticky.messageId;
        const isPlansAndPricingTab = paidTier_1.plansAndPricingTitle === store.tabTitle;
        if (mode === 'freetier-limit') {
            mynahUi.updateStore(tabId, {
                promptInputStickyCard: paidTier_1.freeTierLimitSticky,
            });
            if (!isFreeTierLimitUi) {
                // TODO: how to set a warning icon on the user's failed prompt?
                //
                // const chatItems = store.chatItems ?? []
                // const lastPrompt = chatItems.filter(ci => ci.type === ChatItemType.PROMPT).at(-1)
                // for (const c of chatItems) {
                //     c.body = 'xxx / ' + c.type
                //     c.icon = 'warning'
                //     c.iconStatus = 'warning'
                //     c.status = 'warning'
                // }
                //
                // if (lastPrompt && lastPrompt.messageId) {
                //     lastPrompt.icon = 'warning'
                //     lastPrompt.iconStatus = 'warning'
                //     lastPrompt.status = 'warning'
                //
                //     // Decorate the failed prompt with a warning icon.
                //     // mynahUi.updateChatAnswerWithMessageId(tabId, lastPrompt.messageId, lastPrompt)
                // }
                //
                // mynahUi.updateStore(tabId, {
                //     chatItems: chatItems,
                // })
            }
            else {
                // Show directive only on 2nd chat attempt, not the initial attempt.
                mynahUi.addChatItem(tabId, paidTier_1.freeTierLimitDirective);
            }
        }
        else if (mode === 'upgrade-pending') {
            // Change the sticky banner to show a progress spinner.
            const card = {
                ...(isFreeTierLimitUi ? paidTier_1.freeTierLimitSticky : paidTier_1.upgradePendingSticky),
            };
            card.header = {
                ...card.header,
                icon: paidTier_1.upgradePendingSticky.header?.icon,
                iconStatus: paidTier_1.upgradePendingSticky.header?.iconStatus,
            };
            mynahUi.updateStore(tabId, {
                promptInputVisible: true,
                promptInputStickyCard: card,
            });
        }
        else if (mode === 'paidtier') {
            mynahUi.updateStore(tabId, {
                promptInputStickyCard: null,
                promptInputVisible: !isPlansAndPricingTab,
            });
            if (isFreeTierLimitUi || isUpgradePendingUi || isPlansAndPricingTab) {
                // Transitioning from 'upgrade-pending' to upgrade success.
                const card = {
                    ...paidTier_1.upgradeSuccessSticky,
                    canBeDismissed: !isPlansAndPricingTab,
                };
                mynahUi.updateStore(tabId, {
                    promptInputStickyCard: card,
                });
            }
        }
        mynahUi.updateStore(tabId, {
        // promptInputButtons: mode === 'freetier-limit' ? [upgradeQButton] : [],
        // promptInputDisabledState: mode === 'freetier-limit',
        });
        return true;
    };
    const updateChat = (params) => {
        // HACK: Special field sent by `agenticChatController.ts:setPaidTierMode()`.
        if (onPaidTierModeChange(params.tabId, params.paidTierMode)) {
            return;
        }
        const isChatLoading = params.state?.inProgress;
        mynahUi.updateStore(params.tabId, {
            loadingChat: isChatLoading,
            cancelButtonWhenLoading: agenticMode,
        });
        if (params.data?.messages.length) {
            const { tabId } = params;
            const store = mynahUi.getTabData(tabId).getStore() || {};
            const chatItems = store.chatItems || [];
            params.data?.messages.forEach(updatedMessage => {
                if (!updatedMessage.messageId) {
                    // Do not process messages without known ID.
                    return;
                }
                if (updatedMessage.messageId === 'modelUnavailable') {
                    mynahUi.updateStore(tabId, {
                        promptInputStickyCard: modelSelection_1.modelUnavailableBanner,
                    });
                    return;
                }
                if (updatedMessage.messageId === 'modelThrottled') {
                    mynahUi.updateStore(tabId, {
                        promptInputStickyCard: modelSelection_1.modelThrottledBanner,
                    });
                    return;
                }
                const oldMessage = chatItems.find(ci => ci.messageId === updatedMessage.messageId);
                if (!oldMessage)
                    return;
                const chatItem = {
                    type: oldMessage.type,
                    ...prepareChatItemFromMessage(updatedMessage, getTabPairProgrammingMode(mynahUi, tabId)),
                };
                mynahUi.updateChatAnswerWithMessageId(tabId, updatedMessage.messageId, chatItem);
            });
        }
    };
    /**
     * Creates a properly formatted chat item for MCP tool summary with accordion view
     */
    const createMcpToolSummaryItem = (message, isPartialResult) => {
        return {
            type: mynah_ui_1.ChatItemType.ANSWER,
            messageId: message.messageId,
            summary: {
                content: message.summary?.content
                    ? {
                        padding: false,
                        wrapCodes: true,
                        header: message.summary.content.header
                            ? {
                                icon: message.summary.content.header.icon,
                                body: message.summary.content.header.body,
                                buttons: message.summary.content?.header?.buttons,
                                status: isPartialResult
                                    ? message.summary.content?.header?.status
                                    : undefined,
                                fileList: undefined,
                            }
                            : undefined,
                    }
                    : undefined,
                collapsedContent: message.summary?.collapsedContent?.map(item => ({
                    body: item.body,
                    header: item.header
                        ? {
                            body: item.header.body,
                        }
                        : undefined,
                    fullWidth: true,
                    padding: false,
                    muted: false,
                    wrapCodes: item.header?.body === 'Parameters' ? true : false,
                    codeBlockActions: { copy: null, 'insert-to-cursor': null },
                })) || [],
            },
        };
    };
    const prepareChatItemFromMessage = (message, isPairProgrammingMode, isPartialResult) => {
        const contextHeader = contextListToHeader(message.contextList);
        const header = contextHeader || (0, utils_1.toMynahHeader)(message.header); // Is this mutually exclusive?
        const fileList = (0, utils_1.toMynahFileList)(message.fileList);
        let processedHeader = header;
        if (message.type === 'tool') {
            // Handle MCP tool summary with accordion view
            if (message.summary) {
                return createMcpToolSummaryItem(message, isPartialResult);
            }
            processedHeader = { ...header };
            if (header?.buttons) {
                processedHeader.buttons = header.buttons.map(button => ({
                    ...button,
                    status: button.status ?? 'clear',
                }));
            }
            if (header?.fileList) {
                processedHeader.fileList = {
                    ...header.fileList,
                    fileTreeTitle: '',
                    hideFileCount: true,
                    details: (0, utils_1.toDetailsWithoutIcon)(header.fileList.details),
                    renderAsPills: !header.fileList.details ||
                        (Object.values(header.fileList.details).every(detail => !detail.changes) &&
                            (!header.buttons || !header.buttons.some(button => button.id === 'undo-changes')) &&
                            !header.status?.icon),
                };
            }
            if (!isPartialResult) {
                if (processedHeader && !message.header?.status) {
                    processedHeader.status = undefined;
                }
            }
        }
        // Check if header should be included
        const includeHeader = processedHeader &&
            ((processedHeader.buttons !== undefined &&
                processedHeader.buttons !== null &&
                processedHeader.buttons.length > 0) ||
                processedHeader.status !== undefined ||
                processedHeader.icon !== undefined ||
                processedHeader.fileList !== undefined);
        const padding = message.type === 'tool' ? (fileList ? true : message.messageId?.endsWith('_permission')) : undefined;
        const processedButtons = (0, utils_1.toMynahButtons)(message.buttons)?.map(button => button.id === 'undo-all-changes' ? { ...button, position: 'outside' } : button);
        // Adding this conditional check to show the stop message in the center.
        const contentHorizontalAlignment = undefined;
        // If message.header?.status?.text is Stopped or Rejected or Ignored etc.. card should be in disabled state.
        const shouldMute = message.header?.status?.text !== undefined &&
            ['Stopped', 'Rejected', 'Ignored', 'Failed', 'Error'].includes(message.header.status.text);
        return {
            body: message.body,
            header: includeHeader ? processedHeader : undefined,
            buttons: processedButtons,
            fileList,
            // file diffs in the header need space
            fullWidth: message.type === 'tool' && includeHeader ? true : undefined,
            padding,
            contentHorizontalAlignment,
            wrapCodes: message.type === 'tool',
            codeBlockActions: message.type === 'tool'
                ? { 'insert-to-cursor': null, copy: null }
                : isPairProgrammingMode
                    ? { 'insert-to-cursor': null }
                    : undefined,
            ...(shouldMute ? { muted: true } : {}),
        };
    };
    const sendToPrompt = (params) => {
        const tabId = getOrCreateTabId();
        if (!tabId)
            return;
        chatHistoryList.close();
        mcpMynahUi.close();
        if (params.autoSubmit && params.prompt) {
            messager.onChatPrompt({ prompt: params.prompt, tabId, context: undefined }, 'contextMenu');
            initializeChatResponse(mynahUi, tabId, params.prompt.prompt, agenticMode);
        }
        else {
            mynahUi.addToUserPrompt(tabId, params.selection, 'code');
        }
        messager.onSendToPrompt(params, tabId);
    };
    const sendGenericCommand = (params) => {
        let tabId = getOrCreateTabId();
        if (!tabId)
            return;
        chatHistoryList.close();
        mcpMynahUi.close();
        // send to a new tab if the current tab is loading
        if (getTabStore(tabId)?.loadingChat) {
            tabId = createTabId();
            if (!tabId)
                return;
        }
        let body = '';
        let chatPrompt;
        const genericCommandString = params.genericCommand;
        if (genericCommandString.includes('Review')) {
            chatPrompt = { command: '/review' };
            if (!tabFactory?.isCodeReviewInChatEnabled()) {
                customChatClientAdapter?.handleQuickAction(chatPrompt, tabId, '');
                return;
            }
        }
        else {
            body = [
                genericCommandString,
                ' the following part of my code:',
                '\n~~~~\n',
                params.selection,
                '\n~~~~\n',
            ].join('');
            chatPrompt = { prompt: body, escapedPrompt: body };
        }
        (0, exports.handleChatPrompt)(mynahUi, tabId, chatPrompt, messager, params.triggerType, undefined, agenticMode, tabFactory);
    };
    const showError = (params) => {
        const tabId = getOrCreateTabId();
        if (!tabId)
            return;
        const answer = {
            type: mynah_ui_1.ChatItemType.ANSWER,
            body: `**${params.title}**
${params.message}`,
        };
        mynahUi.updateStore(tabId, {
            loadingChat: false,
            cancelButtonWhenLoading: agenticMode,
            promptInputDisabledState: false,
        });
        mynahUi.addChatItem(params.tabId, answer);
        messager.onError(params);
    };
    const executeShellCommandShortCut = (params) => {
        const activeElement = document.activeElement;
        const tabId = mynahUi.getSelectedTabId();
        if (!tabId)
            return;
        const chatItems = mynahUi.getTabData(tabId)?.getStore()?.chatItems || [];
        const buttonId = params.id;
        let messageId;
        for (const item of chatItems) {
            if (buttonId === 'stop-shell-command' && item.buttons && item.buttons.some(b => b.id === buttonId)) {
                messageId = item.messageId;
                break;
            }
            if (item.header?.buttons && item.header.buttons.some(b => b.id === buttonId)) {
                messageId = item.messageId;
                break;
            }
        }
        if (messageId) {
            const payload = {
                tabId,
                messageId,
                buttonId,
            };
            messager.onButtonClick(payload);
            if (buttonId === 'stop-shell-command') {
                handleUIStopChatResponse(messager, mynahUi, tabId);
            }
        }
        else {
            // handle global stop
            const isLoading = mynahUi.getTabData(tabId)?.getStore()?.loadingChat;
            if (isLoading && buttonId === 'stop-shell-command') {
                handleUIStopChatResponse(messager, mynahUi, tabId);
            }
        }
        // this is a short-term solution to re-gain focus after executing a shortcut
        // current behavior will emit exitFocus telemetry immediadately.
        // use this to re-gain focus, so that user can use shortcut after shortcut
        // without manually re-gain focus.
        setTimeout(() => {
            if (activeElement && activeElement.focus) {
                activeElement.focus();
            }
        }, 100);
    };
    const openTab = (requestId, params) => {
        if (params.tabId) {
            if (params.tabId !== mynahUi.getSelectedTabId()) {
                mynahUi.selectTab(params.tabId);
            }
            messager.onOpenTab(requestId, { tabId: params.tabId });
        }
        else {
            const messages = params.newTabOptions?.data?.messages;
            const tabId = createTabId(true);
            if (tabId) {
                mynahUi.updateStore(tabId, {
                    chatItems: tabFactory.getChatItems(messages ? false : true, programmingModeCardActive, messages),
                });
                messager.onOpenTab(requestId, { tabId });
            }
            else {
                messager.onOpenTab(requestId, {
                    type: 'InvalidRequest',
                    message: 'No more tabs available',
                });
            }
        }
    };
    const toContextCommands = (commands) => {
        return commands.map(command => ({
            ...command,
            children: command.children?.map(child => ({
                ...child,
                commands: toContextCommands(child.commands),
            })),
            icon: (0, utils_1.toMynahIcon)(command.icon),
            disabled: command.disabledText != null,
        }));
    };
    const sendPinnedContext = (params) => {
        const pinnedContext = toContextCommands(params.contextCommandGroups[0]?.commands || []);
        let activeEditor = pinnedContext[0]?.id === ACTIVE_EDITOR_CONTEXT_ID;
        // Update Active File pill description with active editor URI passed from IDE
        if (activeEditor) {
            if (params.textDocument != null) {
                pinnedContext[0].description = params.textDocument.uri;
            }
            else {
                // IDE did not pass in active file, remove it from pinned context
                pinnedContext.shift();
                activeEditor = false;
            }
        }
        let promptTopBarTitle = '@';
        // Show full `@Pin Context` title until user adds a pinned context item
        if (pinnedContext.length == 0 || (activeEditor && pinnedContext.length === 1)) {
            promptTopBarTitle = '@Pin Context';
        }
        mynahUi.updateStore(params.tabId, {
            promptTopBarContextItems: pinnedContext,
            promptTopBarTitle,
            promptTopBarButton: params.showRules
                ? { id: 'Rules', status: 'clear', text: 'Rules', icon: 'check-list' }
                : null,
        });
    };
    const sendContextCommands = (params) => {
        contextCommandGroups = params.contextCommandGroups.map(group => ({
            ...group,
            commands: toContextCommands(group.commands),
        }));
        Object.keys(mynahUi.getAllTabs()).forEach(tabId => {
            mynahUi.updateStore(tabId, {
                contextCommands: [
                    ...(contextCommandGroups || []),
                    ...(featureConfig?.get('highlightCommand')
                        ? [
                            {
                                groupName: 'Additional commands',
                                commands: [(0, utils_1.toMynahContextCommand)(featureConfig.get('highlightCommand'))],
                            },
                        ]
                        : []),
                ],
            });
        });
    };
    const addSelectedFilesToContext = (params) => {
        if (params.errorMessage) {
            mynahUi.notify({
                content: params.errorMessage,
                type: mynah_ui_1.NotificationType.ERROR,
            });
            return;
        }
        const commands = [];
        for (const filePath of params.filePaths) {
            const fileName = filePath.split(/[\\/]/).pop() || filePath;
            if (params.fileType === 'image') {
                commands.push({
                    command: fileName,
                    description: filePath,
                    label: 'image',
                    route: [filePath],
                    icon: mynah_ui_1.MynahIcons.IMAGE,
                    id: fileName,
                });
            }
        }
        mynahUi.addCustomContextToPrompt(params.tabId, commands, params.insertPosition);
    };
    const chatHistoryList = new history_1.ChatHistoryList(mynahUi, messager);
    const listConversations = (params) => {
        chatHistoryList.show(params);
    };
    const rulesList = new rules_1.RulesList(mynahUi, messager);
    const listRules = (params) => {
        rulesList.show(params);
    };
    const ruleClicked = (params) => {
        if (!params.success) {
            mynahUi.notify({
                content: `Failed to toggle the workspace rule`,
                type: mynah_ui_1.NotificationType.ERROR,
            });
            return;
        }
        messager.onListRules({ tabId: params.tabId });
    };
    const conversationClicked = (params) => {
        if (!params.success) {
            mynahUi.notify({
                content: `Failed to ${params.action ?? 'open'} the history`,
                type: mynah_ui_1.NotificationType.ERROR,
            });
            return;
        }
        // close history list if conversation item was successfully opened
        if (!params.action) {
            chatHistoryList.close();
            return;
        }
        // request update conversations list if conversation item was successfully deleted
        if (params.action === 'delete') {
            messager.onListConversations();
        }
    };
    // Create an instance of McpMynahUi to handle MCP server functionality
    const mcpMynahUi = new mcpMynahUi_1.McpMynahUi(mynahUi, messager);
    const listMcpServers = (params) => {
        mcpMynahUi.listMcpServers(params);
    };
    // MCP server functionality is now handled by the McpMynahUi class
    /**
     * Handles MCP server click events
     */
    const mcpServerClick = (params) => {
        mcpMynahUi.mcpServerClick(params);
    };
    const getSerializedChat = (requestId, params) => {
        const supportedFormats = ['markdown', 'html'];
        if (!supportedFormats.includes(params.format)) {
            mynahUi.notify({
                content: `Failed to export chat`,
                type: mynah_ui_1.NotificationType.ERROR,
            });
            messager.onGetSerializedChat(requestId, {
                type: 'InvalidRequest',
                message: `Failed to get serialized chat content, ${params.format} is not supported`,
            });
            return;
        }
        try {
            const serializedChat = mynahUi.serializeChat(params.tabId, params.format);
            messager.onGetSerializedChat(requestId, {
                content: serializedChat,
            });
        }
        catch (err) {
            messager.onGetSerializedChat(requestId, {
                type: 'InternalError',
                message: 'Failed to get serialized chat content',
            });
        }
    };
    const listAvailableModels = (params) => {
        const tabId = params.tabId;
        const promptInputOptions = mynahUi.getTabData(tabId).getStore()?.promptInputOptions;
        mynahUi.updateStore(tabId, {
            promptInputOptions: promptInputOptions?.map(option => option.id === 'model-selection'
                ? {
                    ...option,
                    type: 'select',
                    options: params.models.map(model => ({
                        value: model.id,
                        label: model.name,
                        description: model.description ?? '',
                    })),
                    value: params.selectedModelId,
                }
                : option),
        });
    };
    const api = {
        addChatResponse: addChatResponse,
        updateChat: updateChat,
        sendToPrompt: sendToPrompt,
        sendGenericCommand: sendGenericCommand,
        showError: showError,
        openTab: openTab,
        sendContextCommands: sendContextCommands,
        sendPinnedContext: sendPinnedContext,
        executeShellCommandShortCut: executeShellCommandShortCut,
        listConversations: listConversations,
        listRules: listRules,
        conversationClicked: conversationClicked,
        listMcpServers: listMcpServers,
        mcpServerClick: mcpServerClick,
        getSerializedChat: getSerializedChat,
        createTabId: createTabId,
        ruleClicked: ruleClicked,
        listAvailableModels: listAvailableModels,
        addSelectedFilesToContext: addSelectedFilesToContext,
    };
    return [mynahUi, api];
};
exports.createMynahUi = createMynahUi;
const ACTIVE_EDITOR_CONTEXT_ID = 'active-editor';
exports.DEFAULT_HELP_PROMPT = 'What can Amazon Q help me with?';
const DEFAULT_DOC_PROMPT = `You are Amazon Q. Start with a warm greeting, then ask the user to specify what kind of documentation they need. Present common documentation types (like API docs, README, user guides, developer guides, or configuration guides) as clear options. Keep the question brief and friendly. Don't make assumptions about existing content or context. Wait for their response before providing specific guidance.`;
const DEFAULT_TEST_PROMPT = `You are Amazon Q. Start with a warm greeting, then help me generate unit tests`;
const DEFAULT_DEV_PROMPT = `You are Amazon Q. Start with a warm greeting, then ask the user to specify what kind of help they need in code development. Present common questions asked (like Creating a new project, Adding a new feature, Modifying your files). Keep the question brief and friendly. Don't make assumptions about existing content or context. Wait for their response before providing specific guidance.`;
const DEFAULT_REVIEW_PROMPT = `You are Amazon Q. Start with a warm greeting, then use code review tool to perform a diff review code analysis of the open file. If there is no open file, ask what the user would like to review. Please tell the user that the scan is a diff scan.`;
exports.uiComponentsTexts = {
    mainTitle: 'Amazon Q (Preview)',
    copy: 'Copy',
    insertAtCursorLabel: 'Insert at cursor',
    feedbackFormTitle: 'Report an issue',
    feedbackFormOptionsLabel: 'What type of issue would you like to report?',
    feedbackFormCommentLabel: 'Description of issue (optional):',
    feedbackThanks: 'Thanks for your feedback!',
    feedbackReportButtonLabel: 'Report an issue',
    codeSuggestions: 'Code suggestions',
    files: 'file(s)',
    clickFileToViewDiff: 'Click on a file to view diff.',
    showMore: 'Show more',
    save: 'Save',
    cancel: 'Cancel',
    submit: 'Submit',
    stopGenerating: 'Stop',
    copyToClipboard: 'Copied to clipboard',
    noMoreTabsTooltip: 'You can only open ten conversation tabs at a time.',
    codeSuggestionWithReferenceTitle: 'Some suggestions contain code with references.',
    spinnerText: 'Working...',
    macStopButtonShortcut: '&#8679; &#8984; &#9003;',
    windowStopButtonShortcut: 'Ctrl + &#8679; + &#9003;',
};
const getStopGeneratingToolTipText = (os, agenticMode) => {
    if (agenticMode && os) {
        return os === 'darwin'
            ? `Stop:  ${exports.uiComponentsTexts.macStopButtonShortcut}`
            : `Stop:  ${exports.uiComponentsTexts.windowStopButtonShortcut}`;
    }
    return agenticMode ? exports.uiComponentsTexts.stopGenerating : 'Stop generating';
};
const handleUIStopChatResponse = (messenger, mynahUi, tabId) => {
    messenger.onStopChatResponse(tabId);
    // Reset loading state
    mynahUi.updateStore(tabId, {
        loadingChat: false,
        cancelButtonWhenLoading: true,
        promptInputDisabledState: false,
    });
    // Add a small delay before adding the chat item
    setTimeout(() => {
        // Add cancellation message when stop button is clicked
        mynahUi.addChatItem(tabId, {
            type: mynah_ui_1.ChatItemType.DIRECTIVE,
            messageId: 'stopped' + Date.now(),
            body: 'You stopped your current work, please provide additional examples or ask another question.',
        });
    }, 500); // 500ms delay
};
//# sourceMappingURL=mynahUi.js.map