deploy: current vibn theia state
Some checks failed
Playwright Tests / Playwright Tests (ubuntu-22.04, Node.js 22.x) (push) Has been cancelled
3PP License Check / 3PP License Check (11, 22.x, ubuntu-22.04) (push) Has been cancelled
Publish packages to NPM / Perform Publishing (push) Has been cancelled

Made-with: Cursor
This commit is contained in:
2026-02-27 12:01:08 -08:00
commit 8bb5110148
3782 changed files with 640947 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource GmbH.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { FrontendApplicationContribution } from '@theia/core/lib/browser';
import { inject, injectable } from '@theia/core/shared/inversify';
import { HuggingFaceLanguageModelsManager, HuggingFaceModelDescription } from '../common';
import { API_KEY_PREF, MODELS_PREF } from '../common/huggingface-preferences';
import { PreferenceService } from '@theia/core';
const HUGGINGFACE_PROVIDER_ID = 'huggingface';
@injectable()
export class HuggingFaceFrontendApplicationContribution implements FrontendApplicationContribution {
@inject(PreferenceService)
protected preferenceService: PreferenceService;
@inject(HuggingFaceLanguageModelsManager)
protected manager: HuggingFaceLanguageModelsManager;
protected prevModels: string[] = [];
onStart(): void {
this.preferenceService.ready.then(() => {
const apiKey = this.preferenceService.get<string>(API_KEY_PREF, undefined);
this.manager.setApiKey(apiKey);
const models = this.preferenceService.get<string[]>(MODELS_PREF, []);
this.manager.createOrUpdateLanguageModels(...models.map(modelId => this.createHuggingFaceModelDescription(modelId)));
this.prevModels = [...models];
this.preferenceService.onPreferenceChanged(event => {
if (event.preferenceName === API_KEY_PREF) {
const newApiKey = this.preferenceService.get<string>(API_KEY_PREF, undefined);
this.manager.setApiKey(newApiKey);
this.handleKeyChange(newApiKey);
} else if (event.preferenceName === MODELS_PREF) {
this.handleModelChanges(this.preferenceService.get<string[]>(MODELS_PREF, []));
}
});
});
}
protected handleModelChanges(newModels: string[]): void {
const oldModels = new Set(this.prevModels);
const updatedModels = new Set(newModels);
const modelsToRemove = [...oldModels].filter(model => !updatedModels.has(model));
const modelsToAdd = [...updatedModels].filter(model => !oldModels.has(model));
this.manager.removeLanguageModels(...modelsToRemove.map(model => `${HUGGINGFACE_PROVIDER_ID}/${model}`));
this.manager.createOrUpdateLanguageModels(...modelsToAdd.map(modelId => this.createHuggingFaceModelDescription(modelId)));
this.prevModels = newModels;
}
/**
* Called when the API key changes. Updates all HuggingFace models on the manager to ensure the new key is used.
*/
protected handleKeyChange(newApiKey: string | undefined): void {
if (this.prevModels && this.prevModels.length > 0) {
this.manager.createOrUpdateLanguageModels(...this.prevModels.map(modelId => this.createHuggingFaceModelDescription(modelId)));
}
}
protected createHuggingFaceModelDescription(
modelId: string
): HuggingFaceModelDescription {
const id = `${HUGGINGFACE_PROVIDER_ID}/${modelId}`;
return {
id: id,
model: modelId
};
}
}

View File

@@ -0,0 +1,32 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource GmbH.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { ContainerModule } from '@theia/core/shared/inversify';
import { HuggingFacePreferencesSchema } from '../common/huggingface-preferences';
import { FrontendApplicationContribution, RemoteConnectionProvider, ServiceConnectionProvider } from '@theia/core/lib/browser';
import { HuggingFaceFrontendApplicationContribution } from './huggingface-frontend-application-contribution';
import { HUGGINGFACE_LANGUAGE_MODELS_MANAGER_PATH, HuggingFaceLanguageModelsManager } from '../common';
import { PreferenceContribution } from '@theia/core';
export default new ContainerModule(bind => {
bind(PreferenceContribution).toConstantValue({ schema: HuggingFacePreferencesSchema });
bind(HuggingFaceFrontendApplicationContribution).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(HuggingFaceFrontendApplicationContribution);
bind(HuggingFaceLanguageModelsManager).toDynamicValue(ctx => {
const provider = ctx.container.get<ServiceConnectionProvider>(RemoteConnectionProvider);
return provider.createProxy<HuggingFaceLanguageModelsManager>(HUGGINGFACE_LANGUAGE_MODELS_MANAGER_PATH);
}).inSingletonScope();
});

View File

@@ -0,0 +1,36 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource GmbH.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
export const HUGGINGFACE_LANGUAGE_MODELS_MANAGER_PATH = '/services/huggingface/language-model-manager';
export const HuggingFaceLanguageModelsManager = Symbol('HuggingFaceLanguageModelsManager');
export interface HuggingFaceModelDescription {
/**
* The identifier of the model which will be shown in the UI.
*/
id: string;
/**
* The model ID as used by the Hugging Face API.
*/
model: string;
}
export interface HuggingFaceLanguageModelsManager {
apiKey: string | undefined;
setApiKey(key: string | undefined): void;
createOrUpdateLanguageModels(...models: HuggingFaceModelDescription[]): Promise<void>;
removeLanguageModels(...modelIds: string[]): void;
}

View File

@@ -0,0 +1,46 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource GmbH.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { AI_CORE_PREFERENCES_TITLE } from '@theia/ai-core/lib/common/ai-core-preferences';
import { nls, PreferenceSchema } from '@theia/core';
export const API_KEY_PREF = 'ai-features.huggingFace.apiKey';
export const MODELS_PREF = 'ai-features.huggingFace.models';
export const HuggingFacePreferencesSchema: PreferenceSchema = {
properties: {
[API_KEY_PREF]: {
type: 'string',
markdownDescription: nls.localize('theia/ai/huggingFace/apiKey/mdDescription',
'Enter an API Key for your Hugging Face Account. **Please note:** By using this preference the Hugging Face API key will be stored in clear text\
on the machine running Theia. Use the environment variable `HUGGINGFACE_API_KEY` to set the key securely.'),
title: AI_CORE_PREFERENCES_TITLE,
tags: ['experimental']
},
[MODELS_PREF]: {
type: 'array',
markdownDescription: nls.localize('theia/ai/huggingFace/models/mdDescription',
'Hugging Face models to use. **Please note:** Only models supporting the chat completion API are supported \
(instruction-tuned models like `*-Instruct`) currently. Some models may require accepting license terms on the Hugging Face website.'),
title: AI_CORE_PREFERENCES_TITLE,
default: ['meta-llama/Llama-3.2-3B-Instruct', 'meta-llama/Llama-3.1-8B-Instruct'],
items: {
type: 'string'
},
tags: ['experimental']
}
}
};

View File

@@ -0,0 +1,16 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource GmbH.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
export * from './huggingface-language-models-manager';

View File

@@ -0,0 +1,38 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource GmbH.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { ContainerModule } from '@theia/core/shared/inversify';
import { HUGGINGFACE_LANGUAGE_MODELS_MANAGER_PATH, HuggingFaceLanguageModelsManager } from '../common/huggingface-language-models-manager';
import { ConnectionHandler, PreferenceContribution, RpcConnectionHandler } from '@theia/core';
import { ConnectionContainerModule } from '@theia/core/lib/node/messaging/connection-container-module';
import { HuggingFaceLanguageModelsManagerImpl } from './huggingface-language-models-manager-impl';
import { HuggingFacePreferencesSchema } from '../common/huggingface-preferences';
export const HuggingFaceModelFactory = Symbol('HuggingFaceModelFactory');
// We use a connection module to handle AI services separately for each frontend.
const huggingfaceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService, bindFrontendService }) => {
bind(HuggingFaceLanguageModelsManagerImpl).toSelf().inSingletonScope();
bind(HuggingFaceLanguageModelsManager).toService(HuggingFaceLanguageModelsManagerImpl);
bind(ConnectionHandler).toDynamicValue(ctx =>
new RpcConnectionHandler(HUGGINGFACE_LANGUAGE_MODELS_MANAGER_PATH, () => ctx.container.get(HuggingFaceLanguageModelsManager))
).inSingletonScope();
});
export default new ContainerModule(bind => {
bind(PreferenceContribution).toConstantValue({ schema: HuggingFacePreferencesSchema });
bind(ConnectionContainerModule).toConstantValue(huggingfaceConnectionModule);
});

View File

@@ -0,0 +1,148 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource GmbH.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import {
LanguageModel,
LanguageModelRequest,
LanguageModelMessage,
LanguageModelResponse,
LanguageModelStreamResponsePart,
LanguageModelTextResponse,
MessageActor,
LanguageModelStatus
} from '@theia/ai-core';
import { CancellationToken } from '@theia/core';
import { InferenceClient } from '@huggingface/inference';
export const HuggingFaceModelIdentifier = Symbol('HuggingFaceModelIdentifier');
function toRole(actor: MessageActor): 'user' | 'assistant' | 'system' {
switch (actor) {
case 'user':
return 'user';
case 'ai':
return 'assistant';
case 'system':
return 'system';
default:
return 'user';
}
}
function toChatMessages(messages: LanguageModelMessage[]): Array<{ role: 'user' | 'assistant' | 'system'; content: string }> {
return messages
.filter(LanguageModelMessage.isTextMessage)
.map(message => ({
role: toRole(message.actor),
content: message.text
}));
}
export class HuggingFaceModel implements LanguageModel {
/**
* @param id the unique id for this language model. It will be used to identify the model in the UI.
* @param model the model id as it is used by the Hugging Face API
* @param apiKey function to retrieve the API key for Hugging Face
*/
constructor(
public readonly id: string,
public model: string,
public status: LanguageModelStatus,
public apiKey: () => string | undefined,
public readonly name?: string,
public readonly vendor?: string,
public readonly version?: string,
public readonly family?: string,
public readonly maxInputTokens?: number,
public readonly maxOutputTokens?: number
) { }
async request(request: LanguageModelRequest, cancellationToken?: CancellationToken): Promise<LanguageModelResponse> {
const hfInference = this.initializeInferenceClient();
if (this.isStreamingSupported(this.model)) {
return this.handleStreamingRequest(hfInference, request, cancellationToken);
} else {
return this.handleNonStreamingRequest(hfInference, request);
}
}
protected getSettings(request: LanguageModelRequest): Record<string, unknown> {
return request.settings ?? {};
}
protected async handleNonStreamingRequest(hfInference: InferenceClient, request: LanguageModelRequest): Promise<LanguageModelTextResponse> {
const settings = this.getSettings(request);
const response = await hfInference.chatCompletion({
model: this.model,
messages: toChatMessages(request.messages),
...settings
});
const text = response.choices[0]?.message?.content ?? '';
return {
text
};
}
protected async handleStreamingRequest(
hfInference: InferenceClient,
request: LanguageModelRequest,
cancellationToken?: CancellationToken
): Promise<LanguageModelResponse> {
const settings = this.getSettings(request);
const stream = hfInference.chatCompletionStream({
model: this.model,
messages: toChatMessages(request.messages),
...settings
});
const asyncIterator = {
async *[Symbol.asyncIterator](): AsyncIterator<LanguageModelStreamResponsePart> {
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content;
if (content !== undefined) {
yield { content };
}
if (cancellationToken?.isCancellationRequested) {
break;
}
}
}
};
return { stream: asyncIterator };
}
protected isStreamingSupported(model: string): boolean {
// Assuming all models support streaming for now; can be refined if needed
return true;
}
private initializeInferenceClient(): InferenceClient {
const token = this.apiKey();
if (!token) {
throw new Error('Please provide a Hugging Face API token.');
}
return new InferenceClient(token);
}
}

View File

@@ -0,0 +1,76 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource GmbH.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { LanguageModelRegistry, LanguageModelStatus } from '@theia/ai-core';
import { inject, injectable } from '@theia/core/shared/inversify';
import { HuggingFaceModel } from './huggingface-language-model';
import { HuggingFaceLanguageModelsManager, HuggingFaceModelDescription } from '../common';
@injectable()
export class HuggingFaceLanguageModelsManagerImpl implements HuggingFaceLanguageModelsManager {
protected _apiKey: string | undefined;
@inject(LanguageModelRegistry)
protected readonly languageModelRegistry: LanguageModelRegistry;
get apiKey(): string | undefined {
return this._apiKey ?? process.env.HUGGINGFACE_API_KEY;
}
protected calculateStatus(apiKey: string | undefined): LanguageModelStatus {
return apiKey ? { status: 'ready' } : { status: 'unavailable', message: 'No Hugging Face API key set' };
}
async createOrUpdateLanguageModels(...modelDescriptions: HuggingFaceModelDescription[]): Promise<void> {
for (const modelDescription of modelDescriptions) {
const model = await this.languageModelRegistry.getLanguageModel(modelDescription.id);
const apiKeyProvider = () => this.apiKey;
const status = this.calculateStatus(this.apiKey);
if (model) {
if (!(model instanceof HuggingFaceModel)) {
console.warn(`Hugging Face: model ${modelDescription.id} is not a Hugging Face model`);
continue;
}
await this.languageModelRegistry.patchLanguageModel(modelDescription.id, { status });
} else {
this.languageModelRegistry.addLanguageModels([
new HuggingFaceModel(
modelDescription.id,
modelDescription.model,
status,
apiKeyProvider,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
)
]);
}
}
}
removeLanguageModels(...modelIds: string[]): void {
this.languageModelRegistry.removeLanguageModels(modelIds);
}
setApiKey(apiKey: string | undefined): void {
this._apiKey = apiKey || undefined;
}
}

View File

@@ -0,0 +1,28 @@
// *****************************************************************************
// Copyright (C) 2024 EclipseSource GmbH and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
/* note: this bogus test file is required so that
we are able to run mocha unit tests on this
package, without having any actual unit tests in it.
This way a coverage report will be generated,
showing 0% coverage, instead of no report.
This file can be removed once we have real unit
tests in place. */
describe('ai-huggingface package', () => {
it('support code coverage statistics', () => true);
});