"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NLController = void 0;
const schema_1 = require("langchain/schema");
const callbacks_1 = require("langchain/callbacks");
const openai_1 = require("langchain/chat_models/openai");
const NLView_1 = require("../views/NLView");
class NLController {
    constructor({ filePaths, systemPromptController, conversationHistoryController, tokenController, }) {
        this.nlView = new NLView_1.NLView();
        this.nlmdView = new NLView_1.NLMDView();
        // NLController responsible for appending filepaths to SPC
        this.systemPromptController = systemPromptController;
        this.systemPromptController.addFilePaths(filePaths);
        this.conversationHistoryController = conversationHistoryController;
        this.tokenController = tokenController;
    }
    handleNL(nl, rlCallback) {
        var _a, _b;
        return __awaiter(this, void 0, void 0, function* () {
            if ((yield this.tokenController.areTheAddedFilesTooLarge()) ||
                (yield this.tokenController.isNLInputTooLarge(nl))) {
                this.nlView.renderNLError("Natural Language input is ignored");
                return;
            }
            // append the nl
            this.conversationHistoryController.appendUserMessage(nl);
            const chatMessages = yield this.getChatMessages();
            // const { startCB, streamCB, endCB } = await this.getStreamCBs();
            const { startCB, streamCB, endCB } = yield this.getStreamMDCBs();
            const callbackManager = callbacks_1.CallbackManager.fromHandlers({
                handleLLMStart(llm, _prompts) {
                    return __awaiter(this, void 0, void 0, function* () {
                        yield startCB();
                    });
                },
                handleLLMEnd(output) {
                    return __awaiter(this, void 0, void 0, function* () {
                        yield endCB();
                    });
                },
                handleLLMNewToken(token) {
                    return __awaiter(this, void 0, void 0, function* () {
                        yield streamCB(token);
                    });
                },
            });
            const chat = new openai_1.ChatOpenAI({
                modelName: (_a = process.env.MODEL_NAME) !== null && _a !== void 0 ? _a : "gpt-3.5-turbo-16k",
                temperature: 0.4,
                maxTokens: (_b = Number(process.env.MAX_COMPLETION_TOKENS)) !== null && _b !== void 0 ? _b : 100,
                streaming: true,
                callbackManager,
            });
            const aiReponse = yield chat.call(chatMessages);
            // console.log(`\n===\nai reponse: ${aiReponse.text}\n===\n`);
            this.conversationHistoryController.appendAIMessage(aiReponse.text);
            rlCallback();
        });
    }
    // private
    getChatMessages() {
        return __awaiter(this, void 0, void 0, function* () {
            const systemPromptString = yield this.systemPromptController.getSystemPrompt();
            // truncation
            const truncatedCH = yield this.tokenController.getTruncatedConversationhistory();
            const systemMessage = new schema_1.SystemChatMessage(systemPromptString);
            const convoMessageArray = truncatedCH.map((message, ind) => {
                if (message.key === "ai") {
                    return new schema_1.AIChatMessage(message.content);
                }
                else {
                    const content = message.content +
                        (ind === truncatedCH.length - 1
                            ? "\n\n<|BACKGROUND INSTRUCTION: respond in standard markdown with italics & bolds but don't insert italics/bolds within codeblocks|>"
                            : "");
                    return new schema_1.HumanChatMessage(content);
                }
            });
            const fullMessageArray = [systemMessage, ...convoMessageArray];
            return fullMessageArray;
        });
    }
    // can you give me multiple examples about typescript
    getStreamMDCBs() {
        return __awaiter(this, void 0, void 0, function* () {
            this.nlmdView.buffer = [];
            this.nlmdView.isCodeBlock = false;
            let debugBuffer = [];
            const startCB = () => __awaiter(this, void 0, void 0, function* () {
                this.nlmdView.handleStartCB();
            });
            const streamCB = (token) => __awaiter(this, void 0, void 0, function* () {
                debugBuffer.push(token);
                this.nlmdView.handleStreamCB(token);
            });
            const endCB = () => __awaiter(this, void 0, void 0, function* () {
                // delayedNum doesnt have the latest ai message yet
                const delayedNum = yield this.tokenController.getTokensUsedBySPCH();
                const actualNum = delayedNum + debugBuffer.length;
                this.nlmdView.handleEndCB(actualNum);
                // console.log("--------------"); // check MD output
                // this.nlView.render(debugBuffer.join("|"));
            });
            return { startCB, streamCB, endCB };
        });
    }
}
exports.NLController = NLController;
