"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtHostChatAgents = void 0;
exports.createChatApiFactory = createChatApiFactory;
exports.convertProgress = convertProgress;
const tslib_1 = require("tslib");
const ide_core_common_1 = require("@opensumi/ide-core-common");
const sumi_1 = require("../../../common/sumi");
const typeConverters = tslib_1.__importStar(require("../../../common/vscode/converter"));
class ExtHostChatAgents {
    constructor(rpcProtocol) {
        this.rpcProtocol = rpcProtocol;
        this.agents = new Map();
        this.logger = (0, ide_core_common_1.getDebugLogger)();
        this.previousResultMap = new Map();
        this.resultsBySessionAndRequestId = new Map();
        this.proxy = this.rpcProtocol.getProxy(sumi_1.MainThreadSumiAPIIdentifier.MainThreadChatAgents);
    }
    createChatAgent(extension, name, handler) {
        const handle = ExtHostChatAgents.idPool++;
        const agent = new ExtHostChatAgent(extension, name, this.proxy, handle, handler);
        this.agents.set(handle, agent);
        this.proxy.$registerAgent(handle, name, {});
        return agent.apiAgent;
    }
    createInlineChatAgent(extension, name, handler) {
        const handle = ExtHostChatAgents.idPool++;
        const agent = new ExtHostChatAgent(extension, name, this.proxy, handle, handler);
        this.agents.set(handle, agent);
        this.proxy.$registerInlineChatProvider(handle, name, {});
        return agent.apiInlineChatAgent;
    }
    sendMessage(extension, chunk) {
        let messagePayload;
        if ('content' in chunk) {
            messagePayload =
                typeof chunk.content === 'string'
                    ? { content: chunk.content, kind: 'content' }
                    : { content: typeConverters.MarkdownString.from(chunk.content), kind: 'markdownContent' };
        }
        if ('component' in chunk) {
            messagePayload = {
                component: `${extension.identifier.value}:${chunk.component}`,
                value: chunk.value,
                kind: 'component',
            };
        }
        if (!messagePayload) {
            return;
        }
        this.proxy.$sendMessage(messagePayload);
    }
    async $invokeAgent(handle, request, context, token) {
        const { sessionId, requestId, command, message } = request;
        this.previousResultMap.delete(sessionId);
        const agent = this.agents.get(handle);
        if (!agent) {
            throw new Error(`[CHAT](${handle}) CANNOT invoke agent because the agent is not registered`);
        }
        let done = false;
        function throwIfDone() {
            if (done) {
                throw new Error('Only valid while executing the command');
            }
        }
        const slashCommand = command ? await agent.validateSlashCommand(command) : undefined;
        try {
            const task = agent.invoke({
                prompt: message,
                variables: {}, // TODO: support # variables
                slashCommand,
            }, { history: context.history.map(typeConverters.ChatMessage.to) }, 
            // 暂时只支持 { content: string } 格式的数据
            new ide_core_common_1.Progress((progress) => {
                throwIfDone();
                const convertedProgress = convertProgress(progress, agent.extension);
                if (!convertedProgress) {
                    this.logger.error('Unknown progress type: ' + JSON.stringify(progress));
                    return;
                }
                if ('placeholder' in progress && 'resolvedContent' in progress) {
                    const resolvedContent = Promise.all([
                        this.proxy.$handleProgressChunk(requestId, convertedProgress),
                        progress.resolvedContent,
                    ]);
                    (0, ide_core_common_1.raceCancellation)(resolvedContent, token).then((res) => {
                        if (!res) {
                            return; /* Cancelled */
                        }
                        const [progressHandle, progressContent] = res;
                        const convertedContent = convertProgress(progressContent, agent.extension);
                        if (!convertedContent) {
                            this.logger.error('Unknown progress type: ' + JSON.stringify(progressContent));
                            return;
                        }
                        this.proxy.$handleProgressChunk(requestId, convertedContent, progressHandle !== null && progressHandle !== void 0 ? progressHandle : undefined);
                    });
                }
                else {
                    this.proxy.$handleProgressChunk(requestId, convertedProgress);
                }
            }), token);
            const result = await (0, ide_core_common_1.raceCancellation)(Promise.resolve(task), token);
            if (result) {
                this.previousResultMap.set(sessionId, result);
                let sessionResults = this.resultsBySessionAndRequestId.get(sessionId);
                if (!sessionResults) {
                    sessionResults = new Map();
                    this.resultsBySessionAndRequestId.set(sessionId, sessionResults);
                }
                sessionResults.set(requestId, result);
                return { errorDetails: result.errorDetails };
            }
            else {
                this.previousResultMap.delete(sessionId);
            }
        }
        catch (e) {
            this.logger.error(e, agent.extension);
            return { errorDetails: { message: (e === null || e === void 0 ? void 0 : e.message) || '' } };
        }
        finally {
            done = true;
        }
    }
    $releaseSession(sessionId) {
        this.previousResultMap.delete(sessionId);
        this.resultsBySessionAndRequestId.delete(sessionId);
    }
    async $provideSlashCommands(handle, token) {
        const agent = this.agents.get(handle);
        if (!agent) {
            return [];
        }
        return agent.provideSlashCommand(token);
    }
    $provideFollowups(handle, sessionId, token) {
        const agent = this.agents.get(handle);
        if (!agent) {
            return Promise.resolve([]);
        }
        const result = this.previousResultMap.get(sessionId);
        if (!result) {
            return Promise.resolve([]);
        }
        return agent.provideFollowups(result, token);
    }
    async $provideSampleQuestions(handle, token) {
        const agent = this.agents.get(handle);
        if (!agent) {
            return [];
        }
        return agent.provideSampleQuestions(token);
    }
    async $provideChatWelcomeMessage(handle, token) {
        const agent = this.agents.get(handle);
        if (!agent) {
            return;
        }
        return agent.provideChatWelcomeMessage(token);
    }
}
exports.ExtHostChatAgents = ExtHostChatAgents;
ExtHostChatAgents.idPool = 0;
class ExtHostChatAgent {
    constructor(extension, _id, _proxy, _handle, _callback) {
        this.extension = extension;
        this._id = _id;
        this._proxy = _proxy;
        this._handle = _handle;
        this._callback = _callback;
        this._onDidReceiveFeedback = new ide_core_common_1.Emitter();
        this._onDidPerformAction = new ide_core_common_1.Emitter();
    }
    acceptFeedback(feedback) {
        this._onDidReceiveFeedback.fire(feedback);
    }
    acceptAction(event) {
        this._onDidPerformAction.fire(event);
    }
    async invokeCompletionProvider(query, token) {
        var _a;
        if (!this._agentVariableProvider) {
            return [];
        }
        return (_a = (await this._agentVariableProvider.provider.provideCompletionItems(query, token))) !== null && _a !== void 0 ? _a : [];
    }
    async validateSlashCommand(command) {
        if (!this._lastSlashCommands) {
            await this.provideSlashCommand(ide_core_common_1.CancellationToken.None);
            if (!this._lastSlashCommands) {
                throw Error(`Unknown slashCommand: ${command}`);
            }
        }
        const result = this._lastSlashCommands.find((candidate) => candidate.name === command);
        if (!result) {
            throw new Error(`Unknown slashCommand: ${command}`);
        }
        return result;
    }
    async provideSlashCommand(token) {
        if (!this._slashCommandProvider) {
            return [];
        }
        const result = await this._slashCommandProvider.provideSlashCommands(token);
        if (!result) {
            return [];
        }
        this._lastSlashCommands = result;
        return result.map((c) => ({
            name: c.name,
            description: c.description,
            followupPlaceholder: c.followupPlaceholder,
            shouldRepopulate: c.shouldRepopulate,
            sampleRequest: c.sampleRequest,
            isShortcut: c.isShortcut,
        }));
    }
    async provideFollowups(result, token) {
        if (!this._followupProvider) {
            return [];
        }
        const followups = await this._followupProvider.provideFollowups(result, token);
        if (!followups) {
            return [];
        }
        return followups.map((f) => typeConverters.ChatFollowup.from(f));
    }
    async provideSampleQuestions(token) {
        if (!this._sampleQuestionProvider) {
            return [];
        }
        const result = await this._sampleQuestionProvider.provideSampleQuestions(token);
        if (!result) {
            return [];
        }
        return result.map((f) => typeConverters.ChatReplyFollowup.from(f));
    }
    async provideChatWelcomeMessage(token) {
        var _a;
        if (!this._chatWelcomeMessageProvider) {
            return;
        }
        const result = await this._chatWelcomeMessageProvider.provideChatWelcomeMessage(token);
        if (!result) {
            return;
        }
        return {
            ...result,
            sampleQuestions: ((_a = result.sampleQuestions) !== null && _a !== void 0 ? _a : []).map((f) => typeConverters.ChatReplyFollowup.from(f)),
        };
    }
    get apiInlineChatAgent() {
        let disposed = false;
        const that = this;
        return {
            dispose() {
                disposed = true;
                that._proxy.$unregisterAgent(that._handle);
            },
        };
    }
    get apiAgent() {
        let disposed = false;
        let updateScheduled = false;
        const updateMetadataSoon = () => {
            if (disposed) {
                return;
            }
            if (updateScheduled) {
                return;
            }
            updateScheduled = true;
            queueMicrotask(() => {
                var _a;
                this._proxy.$updateAgent(this._handle, {
                    description: (_a = this._description) !== null && _a !== void 0 ? _a : '',
                    fullName: this._fullName,
                    hasSlashCommands: this._slashCommandProvider !== undefined,
                    hasFollowups: this._followupProvider !== undefined,
                    hasSampleQuestions: this._sampleQuestionProvider !== undefined,
                    hasChatWelcomMessage: this._chatWelcomeMessageProvider !== undefined,
                    isDefault: this._isDefault,
                });
                updateScheduled = false;
            });
        };
        const that = this;
        return {
            get name() {
                return that._id;
            },
            get description() {
                var _a;
                return (_a = that._description) !== null && _a !== void 0 ? _a : '';
            },
            set description(v) {
                that._description = v;
                updateMetadataSoon();
            },
            get fullName() {
                var _a, _b;
                return (_b = (_a = that._fullName) !== null && _a !== void 0 ? _a : that.extension.displayName) !== null && _b !== void 0 ? _b : that.extension.name;
            },
            set fullName(v) {
                that._fullName = v;
                updateMetadataSoon();
            },
            get iconPath() {
                return that._iconPath;
            },
            set iconPath(v) {
                that._iconPath = v;
                updateMetadataSoon();
            },
            get slashCommandProvider() {
                return that._slashCommandProvider;
            },
            set slashCommandProvider(v) {
                that._slashCommandProvider = v;
                updateMetadataSoon();
            },
            get followupProvider() {
                return that._followupProvider;
            },
            set followupProvider(v) {
                that._followupProvider = v;
                updateMetadataSoon();
            },
            get isDefault() {
                return that._isDefault;
            },
            set isDefault(v) {
                that._isDefault = v;
                updateMetadataSoon();
            },
            get chatWelcomMessageProvider() {
                return that._chatWelcomeMessageProvider;
            },
            set chatWelcomMessageProvider(v) {
                that._chatWelcomeMessageProvider = v;
                updateMetadataSoon();
            },
            get sampleQuestionProvider() {
                return that._sampleQuestionProvider;
            },
            set sampleQuestionProvider(v) {
                that._sampleQuestionProvider = v;
                updateMetadataSoon();
            },
            get onDidReceiveFeedback() {
                return that._onDidReceiveFeedback.event;
            },
            onDidPerformAction: this._onDidPerformAction.event,
            populateChatInput: (param) => {
                this._proxy.$populateChatInput(this._handle, {
                    command: param.command,
                    prompt: param.prompt,
                });
            },
            dispose() {
                disposed = true;
                that._slashCommandProvider = undefined;
                that._followupProvider = undefined;
                that._onDidReceiveFeedback.dispose();
                that._proxy.$unregisterAgent(that._handle);
            },
        };
    }
    invoke(request, context, progress, token) {
        return this._callback(request, context, progress, token);
    }
}
function createChatApiFactory(extension, extHostChatAgents) {
    return {
        createChatAgent(name, handler) {
            return extHostChatAgents.createChatAgent(extension, name, handler);
        },
        sendMessage(chunk) {
            return extHostChatAgents.sendMessage(extension, chunk);
        },
        // proposed api
        createInlineChatAgent(name, handler) {
            return extHostChatAgents.createInlineChatAgent(extension, name, handler);
        },
    };
}
function convertProgress(progress, extension) {
    if ('placeholder' in progress && 'resolvedContent' in progress) {
        return { content: progress.placeholder, kind: 'asyncContent' };
    }
    else if ('markdownContent' in progress) {
        return { content: typeConverters.MarkdownString.from(progress.markdownContent), kind: 'markdownContent' };
    }
    else if ('content' in progress) {
        if (typeof progress.content === 'string') {
            return { content: progress.content, kind: 'content' };
        }
        return { content: typeConverters.MarkdownString.from(progress.content), kind: 'markdownContent' };
    }
    else if ('treeData' in progress) {
        return { treeData: progress.treeData, kind: 'treeData' };
    }
    else if ('component' in progress) {
        return {
            component: `${extension.identifier.value}:${progress.component}`,
            value: progress.value,
            kind: 'component',
        };
    }
    else {
        return undefined;
    }
}
//# sourceMappingURL=ext.host.chat.impl.js.map