diff --git a/examples/browser-only/package.json b/examples/browser-only/package.json
index e1ed7399bd982..bec4142e20b8c 100644
--- a/examples/browser-only/package.json
+++ b/examples/browser-only/package.json
@@ -21,6 +21,7 @@
"@theia/ai-core": "1.53.0",
"@theia/ai-history": "1.53.0",
"@theia/ai-openai": "1.53.0",
+ "@theia/ai-ollama": "1.53.0",
"@theia/api-samples": "1.53.0",
"@theia/bulk-edit": "1.53.0",
"@theia/callhierarchy": "1.53.0",
diff --git a/examples/browser-only/tsconfig.json b/examples/browser-only/tsconfig.json
index 2d8d29a0d1fa1..2c35a886f30d0 100644
--- a/examples/browser-only/tsconfig.json
+++ b/examples/browser-only/tsconfig.json
@@ -23,6 +23,9 @@
{
"path": "../../packages/ai-history"
},
+ {
+ "path": "../../packages/ai-ollama"
+ },
{
"path": "../../packages/ai-openai"
},
diff --git a/examples/browser/package.json b/examples/browser/package.json
index e6b387674d0b7..21ce9dccb8410 100644
--- a/examples/browser/package.json
+++ b/examples/browser/package.json
@@ -26,6 +26,7 @@
"@theia/ai-core": "1.53.0",
"@theia/ai-history": "1.53.0",
"@theia/ai-openai": "1.53.0",
+ "@theia/ai-ollama": "1.53.0",
"@theia/ai-terminal": "1.53.0",
"@theia/ai-workspace-agent": "1.53.0",
"@theia/api-provider-sample": "1.53.0",
diff --git a/examples/browser/tsconfig.json b/examples/browser/tsconfig.json
index ed5f00cd84c77..f6b8cad219535 100644
--- a/examples/browser/tsconfig.json
+++ b/examples/browser/tsconfig.json
@@ -23,6 +23,9 @@
{
"path": "../../packages/ai-history"
},
+ {
+ "path": "../../packages/ai-ollama"
+ },
{
"path": "../../packages/ai-openai"
},
diff --git a/examples/electron/package.json b/examples/electron/package.json
index 16c72e673eef9..6080cd438088e 100644
--- a/examples/electron/package.json
+++ b/examples/electron/package.json
@@ -32,6 +32,7 @@
"@theia/ai-core": "1.53.0",
"@theia/ai-history": "1.53.0",
"@theia/ai-openai": "1.53.0",
+ "@theia/ai-ollama": "1.53.0",
"@theia/ai-terminal": "1.53.0",
"@theia/ai-workspace-agent": "1.53.0",
"@theia/api-provider-sample": "1.53.0",
diff --git a/examples/electron/tsconfig.json b/examples/electron/tsconfig.json
index b67a624574045..e36e0e73f4457 100644
--- a/examples/electron/tsconfig.json
+++ b/examples/electron/tsconfig.json
@@ -26,6 +26,9 @@
{
"path": "../../packages/ai-history"
},
+ {
+ "path": "../../packages/ai-ollama"
+ },
{
"path": "../../packages/ai-openai"
},
diff --git a/packages/ai-ollama/.eslintrc.js b/packages/ai-ollama/.eslintrc.js
new file mode 100644
index 0000000000000..13089943582b6
--- /dev/null
+++ b/packages/ai-ollama/.eslintrc.js
@@ -0,0 +1,10 @@
+/** @type {import('eslint').Linter.Config} */
+module.exports = {
+ extends: [
+ '../../configs/build.eslintrc.json'
+ ],
+ parserOptions: {
+ tsconfigRootDir: __dirname,
+ project: 'tsconfig.json'
+ }
+};
diff --git a/packages/ai-ollama/README.md b/packages/ai-ollama/README.md
new file mode 100644
index 0000000000000..f9eba7a29e173
--- /dev/null
+++ b/packages/ai-ollama/README.md
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
ECLIPSE THEIA - Ollama EXTENSION
+
+
+
+
+
+## Description
+
+The `@theia/ai-ollama` integrates Ollama's models with Theia AI.
+
+## Additional Information
+
+- [Theia - GitHub](https://github.com/eclipse-theia/theia)
+- [Theia - Website](https://theia-ide.org/)
+
+## License
+
+- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
+- [(Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)
+
+## Trademark
+
+"Theia" is a trademark of the Eclipse Foundation
+
diff --git a/packages/ai-ollama/package.json b/packages/ai-ollama/package.json
new file mode 100644
index 0000000000000..779515df07d0b
--- /dev/null
+++ b/packages/ai-ollama/package.json
@@ -0,0 +1,53 @@
+{
+ "name": "@theia/ai-ollama",
+ "version": "1.53.0",
+ "description": "Theia - Ollama Integration",
+ "dependencies": {
+ "@theia/core": "1.53.0",
+ "@theia/filesystem": "1.53.0",
+ "@theia/workspace": "1.53.0",
+ "minimatch": "^5.1.0",
+ "tslib": "^2.6.2",
+ "ollama": "^0.5.8",
+ "@theia/ai-core": "1.53.0"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "theiaExtensions": [
+ {
+ "frontend": "lib/browser/ollama-frontend-module",
+ "backend": "lib/node/ollama-backend-module"
+ }
+ ],
+ "keywords": [
+ "theia-extension"
+ ],
+ "license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/eclipse-theia/theia.git"
+ },
+ "bugs": {
+ "url": "https://github.com/eclipse-theia/theia/issues"
+ },
+ "homepage": "https://github.com/eclipse-theia/theia",
+ "files": [
+ "lib",
+ "src"
+ ],
+ "scripts": {
+ "build": "theiaext build",
+ "clean": "theiaext clean",
+ "compile": "theiaext compile",
+ "lint": "theiaext lint",
+ "test": "theiaext test",
+ "watch": "theiaext watch"
+ },
+ "devDependencies": {
+ "@theia/ext-scripts": "1.53.0"
+ },
+ "nyc": {
+ "extends": "../../configs/nyc.json"
+ }
+}
diff --git a/packages/ai-ollama/src/browser/ollama-frontend-application-contribution.ts b/packages/ai-ollama/src/browser/ollama-frontend-application-contribution.ts
new file mode 100644
index 0000000000000..e08680563cd72
--- /dev/null
+++ b/packages/ai-ollama/src/browser/ollama-frontend-application-contribution.ts
@@ -0,0 +1,59 @@
+// *****************************************************************************
+// Copyright (C) 2024 TypeFox 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, PreferenceService } from '@theia/core/lib/browser';
+import { inject, injectable } from '@theia/core/shared/inversify';
+import { OllamaLanguageModelsManager } from '../common';
+import { HOST_PREF, MODELS_PREF } from './ollama-preferences';
+
+@injectable()
+export class OllamaFrontendApplicationContribution implements FrontendApplicationContribution {
+
+ @inject(PreferenceService)
+ protected preferenceService: PreferenceService;
+
+ @inject(OllamaLanguageModelsManager)
+ protected manager: OllamaLanguageModelsManager;
+
+ protected prevModels: string[] = [];
+
+ onStart(): void {
+ this.preferenceService.ready.then(() => {
+ const host = this.preferenceService.get(HOST_PREF, 'http://localhost:11434');
+ this.manager.setHost(host);
+
+ const models = this.preferenceService.get(MODELS_PREF, []);
+ this.manager.createLanguageModels(...models);
+ this.prevModels = [...models];
+
+ this.preferenceService.onPreferenceChanged(event => {
+ if (event.preferenceName === HOST_PREF) {
+ this.manager.setHost(event.newValue);
+ } else if (event.preferenceName === MODELS_PREF) {
+ const oldModels = new Set(this.prevModels);
+ const newModels = new Set(event.newValue as string[]);
+
+ const modelsToRemove = [...oldModels].filter(model => !newModels.has(model));
+ const modelsToAdd = [...newModels].filter(model => !oldModels.has(model));
+
+ this.manager.removeLanguageModels(...modelsToRemove);
+ this.manager.createLanguageModels(...modelsToAdd);
+ this.prevModels = [...event.newValue];
+ }
+ });
+ });
+ }
+}
diff --git a/packages/ai-ollama/src/browser/ollama-frontend-module.ts b/packages/ai-ollama/src/browser/ollama-frontend-module.ts
new file mode 100644
index 0000000000000..7228aba4b4332
--- /dev/null
+++ b/packages/ai-ollama/src/browser/ollama-frontend-module.ts
@@ -0,0 +1,31 @@
+// *****************************************************************************
+// Copyright (C) 2024 TypeFox 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 { OllamaPreferencesSchema } from './ollama-preferences';
+import { FrontendApplicationContribution, PreferenceContribution, RemoteConnectionProvider, ServiceConnectionProvider } from '@theia/core/lib/browser';
+import { OllamaFrontendApplicationContribution } from './ollama-frontend-application-contribution';
+import { OLLAMA_LANGUAGE_MODELS_MANAGER_PATH, OllamaLanguageModelsManager } from '../common';
+
+export default new ContainerModule(bind => {
+ bind(PreferenceContribution).toConstantValue({ schema: OllamaPreferencesSchema });
+ bind(OllamaFrontendApplicationContribution).toSelf().inSingletonScope();
+ bind(FrontendApplicationContribution).toService(OllamaFrontendApplicationContribution);
+ bind(OllamaLanguageModelsManager).toDynamicValue(ctx => {
+ const provider = ctx.container.get(RemoteConnectionProvider);
+ return provider.createProxy(OLLAMA_LANGUAGE_MODELS_MANAGER_PATH);
+ }).inSingletonScope();
+});
diff --git a/packages/ai-ollama/src/browser/ollama-preferences.ts b/packages/ai-ollama/src/browser/ollama-preferences.ts
new file mode 100644
index 0000000000000..b7088001bccc0
--- /dev/null
+++ b/packages/ai-ollama/src/browser/ollama-preferences.ts
@@ -0,0 +1,41 @@
+// *****************************************************************************
+// Copyright (C) 2024 TypeFox 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 { PreferenceSchema } from '@theia/core/lib/browser/preferences/preference-contribution';
+import { AI_CORE_PREFERENCES_TITLE } from '@theia/ai-core/lib/browser/ai-core-preferences';
+
+export const HOST_PREF = 'ai-features.ollama.host';
+export const MODELS_PREF = 'ai-features.ollama.models';
+
+export const OllamaPreferencesSchema: PreferenceSchema = {
+ type: 'object',
+ properties: {
+ [HOST_PREF]: {
+ type: 'string',
+ title: AI_CORE_PREFERENCES_TITLE,
+ description: 'Ollama Host',
+ default: 'http://localhost:11434'
+ },
+ [MODELS_PREF]: {
+ type: 'array',
+ title: AI_CORE_PREFERENCES_TITLE,
+ default: ['llama3', 'gemma2'],
+ items: {
+ type: 'string'
+ }
+ }
+ }
+};
diff --git a/packages/ai-ollama/src/common/index.ts b/packages/ai-ollama/src/common/index.ts
new file mode 100644
index 0000000000000..8d6821f9cc79e
--- /dev/null
+++ b/packages/ai-ollama/src/common/index.ts
@@ -0,0 +1,16 @@
+// *****************************************************************************
+// Copyright (C) 2024 TypeFox 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 './ollama-language-models-manager';
diff --git a/packages/ai-ollama/src/common/ollama-language-models-manager.ts b/packages/ai-ollama/src/common/ollama-language-models-manager.ts
new file mode 100644
index 0000000000000..2714ef3a7757a
--- /dev/null
+++ b/packages/ai-ollama/src/common/ollama-language-models-manager.ts
@@ -0,0 +1,23 @@
+// *****************************************************************************
+// Copyright (C) 2024 TypeFox 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 OLLAMA_LANGUAGE_MODELS_MANAGER_PATH = '/services/ollama/language-model-manager';
+export const OllamaLanguageModelsManager = Symbol('OllamaLanguageModelsManager');
+export interface OllamaLanguageModelsManager {
+ host: string | undefined;
+ setHost(host: string | undefined): void;
+ createLanguageModels(...modelIds: string[]): Promise;
+ removeLanguageModels(...modelIds: string[]): void
+}
diff --git a/packages/ai-ollama/src/node/ollama-backend-module.ts b/packages/ai-ollama/src/node/ollama-backend-module.ts
new file mode 100644
index 0000000000000..667729c7fc4e2
--- /dev/null
+++ b/packages/ai-ollama/src/node/ollama-backend-module.ts
@@ -0,0 +1,30 @@
+// *****************************************************************************
+// Copyright (C) 2024 TypeFox 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 { OLLAMA_LANGUAGE_MODELS_MANAGER_PATH, OllamaLanguageModelsManager } from '../common/ollama-language-models-manager';
+import { ConnectionHandler, RpcConnectionHandler } from '@theia/core';
+import { OllamaLanguageModelsManagerImpl } from './ollama-language-models-manager-impl';
+
+export const OllamaModelFactory = Symbol('OllamaModelFactory');
+
+export default new ContainerModule(bind => {
+ bind(OllamaLanguageModelsManagerImpl).toSelf().inSingletonScope();
+ bind(OllamaLanguageModelsManager).toService(OllamaLanguageModelsManagerImpl);
+ bind(ConnectionHandler).toDynamicValue(ctx =>
+ new RpcConnectionHandler(OLLAMA_LANGUAGE_MODELS_MANAGER_PATH, () => ctx.container.get(OllamaLanguageModelsManager))
+ ).inSingletonScope();
+});
diff --git a/packages/ai-ollama/src/node/ollama-language-model.ts b/packages/ai-ollama/src/node/ollama-language-model.ts
new file mode 100644
index 0000000000000..899305831f7b5
--- /dev/null
+++ b/packages/ai-ollama/src/node/ollama-language-model.ts
@@ -0,0 +1,155 @@
+// *****************************************************************************
+// Copyright (C) 2024 TypeFox 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,
+ LanguageModelParsedResponse,
+ LanguageModelRequest,
+ LanguageModelRequestMessage,
+ LanguageModelResponse,
+ LanguageModelStreamResponsePart,
+ ToolRequest
+} from '@theia/ai-core';
+import { CancellationToken } from '@theia/core';
+import { ChatRequest, ChatResponse, Message, Ollama, Tool } from 'ollama';
+
+export const OllamaModelIdentifier = Symbol('OllamaModelIdentifier');
+
+export class OllamaModel implements LanguageModel {
+
+ protected readonly DEFAULT_REQUEST_SETTINGS: Partial> = {
+ keep_alive: '15m'
+ };
+
+ readonly providerId = 'ollama';
+ readonly vendor: string = 'Ollama';
+
+ constructor(protected readonly model: string, protected host: () => string | undefined) {
+ }
+
+ get id(): string {
+ return this.providerId + '/' + this.model;
+ }
+
+ get name(): string {
+ return this.model;
+ }
+
+ async request(request: LanguageModelRequest, cancellationToken?: CancellationToken): Promise {
+ const ollama = this.initializeOllama();
+
+ if (request.response_format?.type === 'json_schema') {
+ return this.handleStructuredOutputRequest(ollama, request);
+ }
+ const response = await ollama.chat({
+ ...this.DEFAULT_REQUEST_SETTINGS,
+ model: this.model,
+ messages: request.messages.map(this.toOllamaMessage),
+ stream: true,
+ tools: request.tools?.map(this.toOllamaTool),
+ ...request.settings
+ });
+
+ cancellationToken?.onCancellationRequested(() => {
+ response.abort();
+ });
+
+ async function* wrapAsyncIterator(inputIterable: AsyncIterable): AsyncIterable {
+ for await (const item of inputIterable) {
+ // TODO handle tool calls
+ yield { content: item.message.content };
+ }
+ }
+ return { stream: wrapAsyncIterator(response) };
+ }
+
+ protected async handleStructuredOutputRequest(ollama: Ollama, request: LanguageModelRequest): Promise {
+ const result = await ollama.chat({
+ ...this.DEFAULT_REQUEST_SETTINGS,
+ model: this.model,
+ messages: request.messages.map(this.toOllamaMessage),
+ format: 'json',
+ ...request.settings
+ });
+ try {
+ return {
+ content: result.message.content,
+ parsed: JSON.parse(result.message.content)
+ };
+ } catch (error) {
+ // TODO use ILogger
+ console.log('Failed to parse structured response from the language model.', error);
+ return {
+ content: result.message.content,
+ parsed: {}
+ };
+ }
+ }
+
+ protected initializeOllama(): Ollama {
+ const host = this.host();
+ if (!host) {
+ throw new Error('Please provide OLLAMA_HOST in preferences or via environment variable');
+ }
+ return new Ollama({ host: host });
+ }
+
+ protected toOllamaTool(tool: ToolRequest): Tool {
+ const transform = (props: Record | undefined) => {
+ if (!props) {
+ return undefined;
+ }
+ const result: Record = {};
+ for (const key in props) {
+ if (Object.prototype.hasOwnProperty.call(props, key)) {
+ result[key] = {
+ type: props[key].type,
+ description: key
+ };
+ }
+ }
+ return result;
+ };
+ return {
+ type: 'function',
+ function: {
+ name: tool.name,
+ description: tool.description ?? 'Tool named ' + tool.name,
+ parameters: {
+ type: tool.parameters?.type ?? 'object',
+ required: Object.keys(tool.parameters?.properties ?? {}),
+ properties: transform(tool.parameters?.properties) ?? {}
+ },
+ }
+ };
+ }
+
+ protected toOllamaMessage(message: LanguageModelRequestMessage): Message {
+ if (message.actor === 'ai') {
+ return { role: 'assistant', content: message.query || '' };
+ }
+ if (message.actor === 'user') {
+ return { role: 'user', content: message.query || '' };
+ }
+ if (message.actor === 'system') {
+ return { role: 'system', content: message.query || '' };
+ }
+ return { role: 'system', content: '' };
+ }
+}
diff --git a/packages/ai-ollama/src/node/ollama-language-models-manager-impl.ts b/packages/ai-ollama/src/node/ollama-language-models-manager-impl.ts
new file mode 100644
index 0000000000000..1fbd1f520c3c8
--- /dev/null
+++ b/packages/ai-ollama/src/node/ollama-language-models-manager-impl.ts
@@ -0,0 +1,58 @@
+// *****************************************************************************
+// Copyright (C) 2024 TypeFox 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 } from '@theia/ai-core';
+import { inject, injectable } from '@theia/core/shared/inversify';
+import { OllamaModel } from './ollama-language-model';
+import { OllamaLanguageModelsManager } from '../common';
+
+@injectable()
+export class OllamaLanguageModelsManagerImpl implements OllamaLanguageModelsManager {
+
+ protected _host: string | undefined;
+
+ @inject(LanguageModelRegistry)
+ protected readonly languageModelRegistry: LanguageModelRegistry;
+
+ get host(): string | undefined {
+ return this._host ?? process.env.OLLAMA_HOST;
+ }
+
+ // Triggered from frontend. In case you want to use the models on the backend
+ // without a frontend then call this yourself
+ async createLanguageModels(...modelIds: string[]): Promise {
+ for (const id of modelIds) {
+ // TODO check that the model exists in Ollama using `list`. Ask and trigger download if not.
+ if (!(await this.languageModelRegistry.getLanguageModel(`ollama/${id}`))) {
+ this.languageModelRegistry.addLanguageModels([new OllamaModel(id, () => this.host)]);
+ } else {
+ console.info(`Ollama: skip creating model ${id} because it already exists`);
+ }
+ }
+ }
+
+ removeLanguageModels(...modelIds: string[]): void {
+ this.languageModelRegistry.removeLanguageModels(modelIds.map(id => `ollama/${id}`));
+ }
+
+ setHost(host: string | undefined): void {
+ if (host) {
+ this._host = host;
+ } else {
+ this._host = undefined;
+ }
+ }
+}
diff --git a/packages/ai-ollama/src/package.spec.ts b/packages/ai-ollama/src/package.spec.ts
new file mode 100644
index 0000000000000..2b813c28eef54
--- /dev/null
+++ b/packages/ai-ollama/src/package.spec.ts
@@ -0,0 +1,27 @@
+// *****************************************************************************
+// Copyright (C) 2024 TypeFox 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-ollama package', () => {
+ it('support code coverage statistics', () => true);
+});
diff --git a/packages/ai-ollama/tsconfig.json b/packages/ai-ollama/tsconfig.json
new file mode 100644
index 0000000000000..61a997fc14fd1
--- /dev/null
+++ b/packages/ai-ollama/tsconfig.json
@@ -0,0 +1,25 @@
+{
+ "extends": "../../configs/base.tsconfig",
+ "compilerOptions": {
+ "composite": true,
+ "rootDir": "src",
+ "outDir": "lib"
+ },
+ "include": [
+ "src"
+ ],
+ "references": [
+ {
+ "path": "../ai-core"
+ },
+ {
+ "path": "../core"
+ },
+ {
+ "path": "../filesystem"
+ },
+ {
+ "path": "../workspace"
+ }
+ ]
+}
diff --git a/tsconfig.json b/tsconfig.json
index 3ae111513cd48..ee1bdb0025812 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -69,6 +69,9 @@
{
"path": "packages/ai-history"
},
+ {
+ "path": "packages/ai-ollama"
+ },
{
"path": "packages/ai-openai"
},
diff --git a/yarn.lock b/yarn.lock
index df0f13c9de69c..f009f74d98513 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2141,7 +2141,7 @@
"@types/node" "*"
form-data "^4.0.0"
-"@types/node@*", "@types/node@18", "@types/node@>=10.0.0", "@types/node@^10.14.22", "@types/node@^18.11.18":
+"@types/node@*", "@types/node@18", "@types/node@>=10.0.0", "@types/node@^10.14.22", "@types/node@^18.11.18", "@types/node@^20.9.0":
version "18.19.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.18.tgz#7526471b28828d1fef1f7e4960fb9477e6e4369c"
integrity sha512-80CP7B8y4PzZF0GWx15/gVWRrB5y/bIjNI84NK3cmQJu0WZwvmj2WMA5LcofQFVfLqqCSp545+U2LsrVzX36Zg==
@@ -3369,7 +3369,7 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
-base64-js@^1.3.1:
+base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
@@ -4970,13 +4970,13 @@ electron-window@^0.8.0:
dependencies:
is-electron-renderer "^2.0.0"
-electron@^28.2.8:
- version "28.2.10"
- resolved "https://registry.yarnpkg.com/electron/-/electron-28.2.10.tgz#4e168568406a8b1e9b9a5859e988c905b9a57570"
- integrity sha512-0rGBJNogcl2FIRxGRUv9zuMaBP78nSBJW+Bd1U7OGeg8IEkSIbHOhfn71XoGxgbOUSCEXjjyftq4mtAAVbUsZQ==
+electron@^30.1.2:
+ version "30.5.0"
+ resolved "https://registry.yarnpkg.com/electron/-/electron-30.5.0.tgz#917a5dd1adbd6983ff8a96609035c3bff9821841"
+ integrity sha512-20c774PEsCFRzIgpZIaY6t/wTYxam0MfxQt5t+wG8aStHsl81FchUyLbDo4a59goqE7mHjLOdBDlxmZk88IgRw==
dependencies:
"@electron/get" "^2.0.0"
- "@types/node" "^18.11.18"
+ "@types/node" "^20.9.0"
extract-zip "^2.0.1"
emoji-regex@^8.0.0:
@@ -5678,6 +5678,11 @@ fd-slicer@~1.1.0:
dependencies:
pend "~1.2.0"
+fflate@^0.8.2:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea"
+ integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
+
figures@3.2.0, figures@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
@@ -5851,6 +5856,11 @@ follow-redirects@^1.0.0, follow-redirects@^1.15.4:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020"
integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==
+follow-redirects@^1.15.6:
+ version "1.15.9"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1"
+ integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==
+
font-awesome@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
@@ -7142,6 +7152,11 @@ isobject@^3.0.1:
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==
+isomorphic.js@^0.2.4:
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/isomorphic.js/-/isomorphic.js-0.2.5.tgz#13eecf36f2dba53e85d355e11bf9d4208c6f7f88"
+ integrity sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==
+
istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756"
@@ -7610,6 +7625,13 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"
+lib0@^0.2.52, lib0@^0.2.85, lib0@^0.2.86, lib0@^0.2.94:
+ version "0.2.97"
+ resolved "https://registry.yarnpkg.com/lib0/-/lib0-0.2.97.tgz#a68d7c88577ac1910cdbe5204bac070f07c8e0b4"
+ integrity sha512-Q4d1ekgvufi9FiHkkL46AhecfNjznSL9MRNoJRQ76gBHS9OqU2ArfQK0FvBpuxgWeJeNI0LVgAYMIpsGeX4gYg==
+ dependencies:
+ isomorphic.js "^0.2.4"
+
libnpmaccess@7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-7.0.2.tgz#7f056c8c933dd9c8ba771fa6493556b53c5aac52"
@@ -8453,10 +8475,10 @@ mute-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e"
integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==
-nan@^2.14.0, nan@^2.17.0, nan@^2.18.0:
- version "2.18.0"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554"
- integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==
+nan@2.20.0, nan@^2.14.0, nan@^2.17.0, nan@^2.18.0:
+ version "2.20.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3"
+ integrity sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==
nano@^10.1.3:
version "10.1.3"
@@ -8643,6 +8665,16 @@ node-ssh@^12.0.1:
shell-escape "^0.2.0"
ssh2 "^1.5.0"
+nodejs-file-downloader@4.13.0:
+ version "4.13.0"
+ resolved "https://registry.yarnpkg.com/nodejs-file-downloader/-/nodejs-file-downloader-4.13.0.tgz#da87c30081de5ff4e8b864062c98cdec03e66ad0"
+ integrity sha512-nI2fKnmJWWFZF6SgMPe1iBodKhfpztLKJTtCtNYGhm/9QXmWa/Pk9Sv00qHgzEvNLe1x7hjGDRor7gcm/ChaIQ==
+ dependencies:
+ follow-redirects "^1.15.6"
+ https-proxy-agent "^5.0.0"
+ mime-types "^2.1.27"
+ sanitize-filename "^1.6.3"
+
noop-logger@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2"
@@ -9025,6 +9057,13 @@ octicons@^7.1.0:
dependencies:
object-assign "^4.1.1"
+ollama@^0.5.8:
+ version "0.5.8"
+ resolved "https://registry.yarnpkg.com/ollama/-/ollama-0.5.8.tgz#d52f20345b4b49e26734cf2e8749dd95899c2c99"
+ integrity sha512-frBGdfSV34i7JybLZUeyCYDx0CMyDiG4On8xOK+cNRWM04HImhoWgIMpF4p7vTkQumadbSxOteR7SZyKqNmOXg==
+ dependencies:
+ whatwg-fetch "^3.6.20"
+
on-finished@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
@@ -9046,6 +9085,26 @@ onetime@^5.1.0, onetime@^5.1.2:
dependencies:
mimic-fn "^2.1.0"
+open-collaboration-protocol@0.2.0, open-collaboration-protocol@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/open-collaboration-protocol/-/open-collaboration-protocol-0.2.0.tgz#f3f93f22bb5fbb46e3fd31e6bb87f52a9ce6526b"
+ integrity sha512-ZaLMTMyVoJJ0vPjoMXGhNZqiycbfyJPbNCkbI9uHTOYRsvZqreRAFhSd7p9RbxLJNS5xeQGNSfldrhhec94Bmg==
+ dependencies:
+ base64-js "^1.5.1"
+ fflate "^0.8.2"
+ msgpackr "^1.10.2"
+ semver "^7.6.2"
+ socket.io-client "^4.7.5"
+
+open-collaboration-yjs@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/open-collaboration-yjs/-/open-collaboration-yjs-0.2.0.tgz#7c7e30dba444b9f6947fe76ae02a7c3fdaec6172"
+ integrity sha512-HT2JU/HJObIaQMF/MHt5/5VdOnGn+bVTaTJnyYfyaa/vjqg4Z4Glas3Hc9Ua970ssP3cOIRUQoHQumM0giaxrw==
+ dependencies:
+ lib0 "^0.2.94"
+ open-collaboration-protocol "^0.2.0"
+ y-protocols "^1.0.6"
+
open@^7.4.2:
version "7.4.2"
resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321"
@@ -10417,6 +10476,13 @@ safe-regex-test@^1.0.3:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+sanitize-filename@^1.6.3:
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz#755ebd752045931977e30b2025d340d7c9090378"
+ integrity sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==
+ dependencies:
+ truncate-utf8-bytes "^1.0.0"
+
sax@>=0.6.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0"
@@ -10517,6 +10583,11 @@ semver@^7.0.0, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semve
dependencies:
lru-cache "^6.0.0"
+semver@^7.6.2:
+ version "7.6.3"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
+ integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
+
send@0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
@@ -10778,6 +10849,16 @@ socket.io-client@^4.5.3:
engine.io-client "~6.5.2"
socket.io-parser "~4.2.4"
+socket.io-client@^4.7.5:
+ version "4.7.5"
+ resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.5.tgz#919be76916989758bdc20eec63f7ee0ae45c05b7"
+ integrity sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==
+ dependencies:
+ "@socket.io/component-emitter" "~3.1.0"
+ debug "~4.3.2"
+ engine.io-client "~6.5.2"
+ socket.io-parser "~4.2.4"
+
socket.io-parser@~4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83"
@@ -11510,6 +11591,13 @@ trim-repeated@^1.0.0:
dependencies:
escape-string-regexp "^1.0.2"
+truncate-utf8-bytes@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b"
+ integrity sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==
+ dependencies:
+ utf8-byte-length "^1.0.1"
+
ts-api-utils@^1.0.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1"
@@ -11949,6 +12037,11 @@ user-home@^2.0.0:
dependencies:
os-homedir "^1.0.0"
+utf8-byte-length@^1.0.1:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz#f9f63910d15536ee2b2d5dd4665389715eac5c1e"
+ integrity sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==
+
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
@@ -12183,6 +12276,11 @@ whatwg-encoding@^2.0.0:
dependencies:
iconv-lite "0.6.3"
+whatwg-fetch@^3.6.20:
+ version "3.6.20"
+ resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz#580ce6d791facec91d37c72890995a0b48d31c70"
+ integrity sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==
+
whatwg-mimetype@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7"
@@ -12506,6 +12604,13 @@ xterm@^5.3.0:
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0.tgz#867daf9cc826f3d45b5377320aabd996cb0fce46"
integrity sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==
+y-protocols@^1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/y-protocols/-/y-protocols-1.0.6.tgz#66dad8a95752623443e8e28c0e923682d2c0d495"
+ integrity sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==
+ dependencies:
+ lib0 "^0.2.85"
+
y18n@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
@@ -12627,6 +12732,13 @@ yazl@^2.2.2:
dependencies:
buffer-crc32 "~0.2.3"
+yjs@^13.6.7:
+ version "13.6.19"
+ resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.6.19.tgz#66999f41254ab65be8c8e71bd767d124ad600909"
+ integrity sha512-GNKw4mEUn5yWU2QPHRx8jppxmCm9KzbBhB4qJLUJFiiYD0g/tDVgXQ7aPkyh01YO28kbs2J/BEbWBagjuWyejw==
+ dependencies:
+ lib0 "^0.2.86"
+
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"