
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { Emitter } from '../../../../base/common/event.js';
import { Iterable } from '../../../../base/common/iterator.js';
import { DisposableStore, toDisposable } from '../../../../base/common/lifecycle.js';
import { isFalsyOrWhitespace } from '../../../../base/common/strings.js';
import { localize } from '../../../../nls.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.service.js';
import { ExtensionIdentifier } from '../../../../platform/extensions/common/extensions.js';
import { ILogService } from '../../../../platform/log/common/log.service.js';
import { isProposedApiEnabled } from '../../../services/extensions/common/extensions.js';
import { IExtensionService } from '../../../services/extensions/common/extensions.service.js';
import { ExtensionsRegistry } from '../../../services/extensions/common/extensionsRegistry.js';
import { ChatContextKeys } from './chatContextKeys.js';

var ChatMessageRole;
(function (ChatMessageRole) {
    ChatMessageRole[ChatMessageRole["System"] = 0] = "System";
    ChatMessageRole[ChatMessageRole["User"] = 1] = "User";
    ChatMessageRole[ChatMessageRole["Assistant"] = 2] = "Assistant";
})(ChatMessageRole || (ChatMessageRole = {}));
var ChatImageMimeType;
(function (ChatImageMimeType) {
    ChatImageMimeType["PNG"] = "image/png";
    ChatImageMimeType["JPEG"] = "image/jpeg";
    ChatImageMimeType["GIF"] = "image/gif";
    ChatImageMimeType["WEBP"] = "image/webp";
    ChatImageMimeType["BMP"] = "image/bmp";
})(ChatImageMimeType || (ChatImageMimeType = {}));
var ImageDetailLevel;
(function (ImageDetailLevel) {
    ImageDetailLevel["Low"] = "low";
    ImageDetailLevel["High"] = "high";
})(ImageDetailLevel || (ImageDetailLevel = {}));
const languageModelType = {
    type: 'object',
    properties: {
        vendor: {
            type: 'string',
            description: ( localize(4991, "A globally unique vendor of language models."))
        }
    }
};
const languageModelExtensionPoint = ExtensionsRegistry.registerExtensionPoint({
    extensionPoint: 'languageModels',
    jsonSchema: {
        description: ( localize(4992, "Contribute language models of a specific vendor.")),
        oneOf: [
            languageModelType,
            {
                type: 'array',
                items: languageModelType
            }
        ]
    },
    activationEventsGenerator: (contribs, result) => {
        for (const contrib of contribs) {
            result.push(`onLanguageModelChat:${contrib.vendor}`);
        }
    }
});
let LanguageModelsService = class LanguageModelsService {
    constructor(_extensionService, _logService, _contextKeyService) {
        this._extensionService = _extensionService;
        this._logService = _logService;
        this._contextKeyService = _contextKeyService;
        this._store = ( new DisposableStore());
        this._providers = ( new Map());
        this._vendors = ( new Set());
        this._onDidChangeProviders = this._store.add(( new Emitter()));
        this.onDidChangeLanguageModels = this._onDidChangeProviders.event;
        this._hasUserSelectableModels = ChatContextKeys.languageModelsAreUserSelectable.bindTo(this._contextKeyService);
        this._store.add(languageModelExtensionPoint.setHandler((extensions) => {
            this._vendors.clear();
            for (const extension of extensions) {
                if (!isProposedApiEnabled(extension.description, 'chatProvider')) {
                    extension.collector.error(( localize(4993, "This contribution point requires the 'chatProvider' proposal.")));
                    continue;
                }
                for (const item of Iterable.wrap(extension.value)) {
                    if (( this._vendors.has(item.vendor))) {
                        extension.collector.error(( localize(
                            4994,
                            "The vendor '{0}' is already registered and cannot be registered twice",
                            item.vendor
                        )));
                        continue;
                    }
                    if (isFalsyOrWhitespace(item.vendor)) {
                        extension.collector.error(( localize(4995, "The vendor field cannot be empty.")));
                        continue;
                    }
                    if (item.vendor.trim() !== item.vendor) {
                        extension.collector.error(( localize(4996, "The vendor field cannot start or end with whitespace.")));
                        continue;
                    }
                    this._vendors.add(item.vendor);
                }
            }
            const removed = [];
            for (const [identifier, value] of this._providers) {
                if (!( this._vendors.has(value.metadata.vendor))) {
                    this._providers.delete(identifier);
                    removed.push(identifier);
                }
            }
            if (removed.length > 0) {
                this._onDidChangeProviders.fire({ removed });
            }
        }));
    }
    dispose() {
        this._store.dispose();
        this._providers.clear();
    }
    getLanguageModelIds() {
        return Array.from(( this._providers.keys()));
    }
    lookupLanguageModel(identifier) {
        return this._providers.get(identifier)?.metadata;
    }
    async selectLanguageModels(selector) {
        if (selector.vendor) {
            await this._extensionService.activateByEvent(`onLanguageModelChat:${selector.vendor}}`);
        }
        else {
            const all = ( Array.from(this._vendors).map(
                vendor => this._extensionService.activateByEvent(`onLanguageModelChat:${vendor}`)
            ));
            await Promise.all(all);
        }
        const result = [];
        for (const [identifier, model] of this._providers) {
            if ((selector.vendor === undefined || model.metadata.vendor === selector.vendor)
                && (selector.family === undefined || model.metadata.family === selector.family)
                && (selector.version === undefined || model.metadata.version === selector.version)
                && (selector.id === undefined || model.metadata.id === selector.id)
                && (!model.metadata.targetExtensions || ( model.metadata.targetExtensions.some(candidate => ExtensionIdentifier.equals(candidate, selector.extension))))) {
                result.push(identifier);
            }
        }
        this._logService.trace('[LM] selected language models', selector, result);
        return result;
    }
    registerLanguageModelChat(identifier, provider) {
        this._logService.trace('[LM] registering language model chat', identifier, provider.metadata);
        if (!( this._vendors.has(provider.metadata.vendor))) {
            throw ( new Error(`Chat response provider uses UNKNOWN vendor ${provider.metadata.vendor}.`));
        }
        if (( this._providers.has(identifier))) {
            throw ( new Error(
                `Chat response provider with identifier ${identifier} is already registered.`
            ));
        }
        this._providers.set(identifier, provider);
        this._onDidChangeProviders.fire({ added: [{ identifier, metadata: provider.metadata }] });
        this.updateUserSelectableModelsContext();
        return toDisposable(() => {
            this.updateUserSelectableModelsContext();
            if (this._providers.delete(identifier)) {
                this._onDidChangeProviders.fire({ removed: [identifier] });
                this._logService.trace('[LM] UNregistered language model chat', identifier, provider.metadata);
            }
        });
    }
    updateUserSelectableModelsContext() {
        const hasUserSelectableModels = ( Array.from(( this._providers.values())).some(p => p.metadata.isUserSelectable && !p.metadata.isDefault));
        const hasDefaultModel = ( Array.from(( this._providers.values())).some(p => p.metadata.isDefault));
        this._hasUserSelectableModels.set(hasUserSelectableModels && hasDefaultModel);
    }
    async sendChatRequest(identifier, from, messages, options, token) {
        const provider = this._providers.get(identifier);
        if (!provider) {
            throw ( new Error(`Chat response provider with identifier ${identifier} is not registered.`));
        }
        return provider.sendChatRequest(messages, from, options, token);
    }
    computeTokenLength(identifier, message, token) {
        const provider = this._providers.get(identifier);
        if (!provider) {
            throw ( new Error(`Chat response provider with identifier ${identifier} is not registered.`));
        }
        return provider.provideTokenCount(message, token);
    }
};
LanguageModelsService = ( __decorate([
    ( __param(0, IExtensionService)),
    ( __param(1, ILogService)),
    ( __param(2, IContextKeyService))
], LanguageModelsService));

export { ChatImageMimeType, ChatMessageRole, ImageDetailLevel, LanguageModelsService, languageModelExtensionPoint };
