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,10 @@
/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: [
'../../configs/build.eslintrc.json'
],
parserOptions: {
tsconfigRootDir: __dirname,
project: 'tsconfig.json'
}
};

View File

@@ -0,0 +1,32 @@
<div align='center'>
<br />
<img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />
<h2>ECLIPSE THEIA - AI CODE COMPLETION EXTENSION</h2>
<hr />
</div>
## Description
The `@theia/ai-code-completion` extension contributes Ai based code completion.
The user can separately enable code completion items as well as inline code completion.
## Additional Information
- [API documentation for `@theia/ai-code-completion`](https://eclipse-theia.github.io/theia/docs/next/modules/_theia_ai-code-completion.html)
- [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
<https://www.eclipse.org/theia>

View File

@@ -0,0 +1,55 @@
{
"name": "@theia/ai-code-completion",
"version": "1.68.0",
"description": "Theia - AI Core",
"dependencies": {
"@theia/ai-core": "1.68.0",
"@theia/core": "1.68.0",
"@theia/filesystem": "1.68.0",
"@theia/monaco-editor-core": "1.96.302",
"@theia/output": "1.68.0",
"@theia/workspace": "1.68.0",
"tslib": "^2.6.2"
},
"main": "lib/common",
"publishConfig": {
"access": "public"
},
"theiaExtensions": [
{
"frontend": "lib/browser/ai-code-completion-frontend-module",
"backend": "lib/node/ai-code-completion-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.68.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
},
"gitHead": "21358137e41342742707f660b8e222f940a27652"
}

View File

@@ -0,0 +1,39 @@
// *****************************************************************************
// 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 { Agent, AIVariableContribution } from '@theia/ai-core';
import { FrontendApplicationContribution, KeybindingContribution, } from '@theia/core/lib/browser';
import { ContainerModule } from '@theia/core/shared/inversify';
import { AICodeCompletionPreferencesSchema } from '../common/ai-code-completion-preference';
import { AIFrontendApplicationContribution } from './ai-code-frontend-application-contribution';
import { AICodeInlineCompletionsProvider } from './ai-code-inline-completion-provider';
import { CodeCompletionAgent, CodeCompletionAgentImpl } from './code-completion-agent';
import { CodeCompletionPostProcessor, DefaultCodeCompletionPostProcessor } from './code-completion-postprocessor';
import { CodeCompletionVariableContribution } from './code-completion-variable-contribution';
import { PreferenceContribution } from '@theia/core';
export default new ContainerModule(bind => {
bind(CodeCompletionAgentImpl).toSelf().inSingletonScope();
bind(CodeCompletionAgent).toService(CodeCompletionAgentImpl);
bind(Agent).toService(CodeCompletionAgentImpl);
bind(AICodeInlineCompletionsProvider).toSelf().inSingletonScope();
bind(AIFrontendApplicationContribution).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).to(AIFrontendApplicationContribution);
bind(KeybindingContribution).toService(AIFrontendApplicationContribution);
bind(PreferenceContribution).toConstantValue({ schema: AICodeCompletionPreferencesSchema });
bind(CodeCompletionPostProcessor).to(DefaultCodeCompletionPostProcessor).inSingletonScope();
bind(AIVariableContribution).to(CodeCompletionVariableContribution).inSingletonScope();
});

View File

@@ -0,0 +1,153 @@
// *****************************************************************************
// 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 * as monaco from '@theia/monaco-editor-core';
import { AIActivationService } from '@theia/ai-core/lib/browser';
import { Disposable, PreferenceService } from '@theia/core';
import { FrontendApplicationContribution, KeybindingContribution, KeybindingRegistry } from '@theia/core/lib/browser';
import { inject, injectable } from '@theia/core/shared/inversify';
import { InlineCompletionTriggerKind } from '@theia/monaco-editor-core/esm/vs/editor/common/languages';
import {
PREF_AI_INLINE_COMPLETION_AUTOMATIC_ENABLE,
PREF_AI_INLINE_COMPLETION_DEBOUNCE_DELAY,
PREF_AI_INLINE_COMPLETION_EXCLUDED_EXTENSIONS,
PREF_AI_INLINE_COMPLETION_CACHE_CAPACITY
} from '../common/ai-code-completion-preference';
import { AICodeInlineCompletionsProvider } from './ai-code-inline-completion-provider';
import { InlineCompletionDebouncer } from './code-completion-debouncer';
import { CodeCompletionCache } from './code-completion-cache';
@injectable()
export class AIFrontendApplicationContribution implements FrontendApplicationContribution, KeybindingContribution {
@inject(AICodeInlineCompletionsProvider)
private inlineCodeCompletionProvider: AICodeInlineCompletionsProvider;
@inject(PreferenceService)
protected readonly preferenceService: PreferenceService;
@inject(AIActivationService)
protected readonly activationService: AIActivationService;
private completionCache = new CodeCompletionCache();
private debouncer = new InlineCompletionDebouncer();
private debounceDelay: number;
private toDispose = new Map<string, Disposable>();
onDidInitializeLayout(): void {
this.preferenceService.ready.then(() => {
this.handlePreferences();
});
}
protected handlePreferences(): void {
const handler = () => this.handleInlineCompletions();
this.toDispose.set('inlineCompletions', handler());
this.debounceDelay = this.preferenceService.get<number>(PREF_AI_INLINE_COMPLETION_DEBOUNCE_DELAY, 300);
const cacheCapacity = this.preferenceService.get<number>(PREF_AI_INLINE_COMPLETION_CACHE_CAPACITY, 100);
this.completionCache.setMaxSize(cacheCapacity);
this.preferenceService.onPreferenceChanged(event => {
if (event.preferenceName === PREF_AI_INLINE_COMPLETION_AUTOMATIC_ENABLE
|| event.preferenceName === PREF_AI_INLINE_COMPLETION_EXCLUDED_EXTENSIONS) {
this.toDispose.get('inlineCompletions')?.dispose();
this.toDispose.set('inlineCompletions', handler());
}
if (event.preferenceName === PREF_AI_INLINE_COMPLETION_DEBOUNCE_DELAY) {
this.debounceDelay = this.preferenceService.get<number>(PREF_AI_INLINE_COMPLETION_DEBOUNCE_DELAY, 300);
}
if (event.preferenceName === PREF_AI_INLINE_COMPLETION_CACHE_CAPACITY) {
this.completionCache.setMaxSize(this.preferenceService.get<number>(PREF_AI_INLINE_COMPLETION_CACHE_CAPACITY, 100));
}
});
this.activationService.onDidChangeActiveStatus(change => {
this.toDispose.get('inlineCompletions')?.dispose();
this.toDispose.set('inlineCompletions', handler());
});
}
registerKeybindings(keybindings: KeybindingRegistry): void {
keybindings.registerKeybinding({
command: 'editor.action.inlineSuggest.trigger',
keybinding: 'Ctrl+Alt+Space',
when: '!editorReadonly && editorTextFocus'
});
}
protected handleInlineCompletions(): Disposable {
if (!this.activationService.isActive) {
return Disposable.NULL;
}
const automatic = this.preferenceService.get<boolean>(PREF_AI_INLINE_COMPLETION_AUTOMATIC_ENABLE, true);
const excludedExtensions = this.preferenceService.get<string[]>(PREF_AI_INLINE_COMPLETION_EXCLUDED_EXTENSIONS, []);
return monaco.languages.registerInlineCompletionsProvider(
{ scheme: 'file' },
{
provideInlineCompletions: (model, position, context, token) => {
if (!automatic && context.triggerKind === InlineCompletionTriggerKind.Automatic) {
return { items: [] };
}
const fileName = model.uri.toString();
if (excludedExtensions.some(ext => fileName.endsWith(ext))) {
return { items: [] };
}
const completionHandler = async () => {
try {
const cacheKey = this.completionCache.generateKey(fileName, model, position);
const cachedCompletion = this.completionCache.get(cacheKey);
if (cachedCompletion) {
return cachedCompletion;
}
const completion = await this.inlineCodeCompletionProvider.provideInlineCompletions(
model,
position,
context,
token
);
if (completion && completion.items.length > 0) {
this.completionCache.put(cacheKey, completion);
}
return completion;
} catch (error) {
console.error('Error providing inline completions:', error);
return { items: [] };
}
};
if (context.triggerKind === InlineCompletionTriggerKind.Automatic) {
return this.debouncer.debounce(async () => completionHandler(), this.debounceDelay);
} else if (context.triggerKind === InlineCompletionTriggerKind.Explicit) {
return completionHandler();
}
},
freeInlineCompletions: completions => {
this.inlineCodeCompletionProvider.freeInlineCompletions(completions);
}
}
);
}
}

View File

@@ -0,0 +1,53 @@
// *****************************************************************************
// 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 * as monaco from '@theia/monaco-editor-core';
import { inject, injectable } from '@theia/core/shared/inversify';
import { CodeCompletionAgent } from './code-completion-agent';
import { AgentService } from '@theia/ai-core';
@injectable()
export class AICodeInlineCompletionsProvider
implements monaco.languages.InlineCompletionsProvider {
@inject(CodeCompletionAgent)
protected readonly agent: CodeCompletionAgent;
@inject(AgentService)
private readonly agentService: AgentService;
async provideInlineCompletions(
model: monaco.editor.ITextModel,
position: monaco.Position,
context: monaco.languages.InlineCompletionContext,
token: monaco.CancellationToken
): Promise<monaco.languages.InlineCompletions | undefined> {
if (!this.agentService.isEnabled(this.agent.id)) {
return undefined;
}
return this.agent.provideInlineCompletions(
model,
position,
context,
token
);
}
freeInlineCompletions(
completions: monaco.languages.InlineCompletions<monaco.languages.InlineCompletion>
): void {
// nothing to do
}
}

View File

@@ -0,0 +1,165 @@
// *****************************************************************************
// 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 { LanguageModelService } from '@theia/ai-core/lib/browser';
import {
Agent, AgentSpecificVariables, getTextOfResponse,
LanguageModelRegistry, LanguageModelRequirement, PromptService,
PromptVariantSet,
UserRequest
} from '@theia/ai-core/lib/common';
import { generateUuid, ILogger, nls, ProgressService } from '@theia/core';
import { inject, injectable, named } from '@theia/core/shared/inversify';
import * as monaco from '@theia/monaco-editor-core';
import { codeCompletionPrompts } from './code-completion-prompt-template';
import { CodeCompletionPostProcessor } from './code-completion-postprocessor';
import { CodeCompletionVariableContext } from './code-completion-variable-context';
import { FILE, LANGUAGE, PREFIX, SUFFIX } from './code-completion-variables';
export const CodeCompletionAgent = Symbol('CodeCompletionAgent');
export interface CodeCompletionAgent extends Agent {
provideInlineCompletions(model: monaco.editor.ITextModel, position: monaco.Position,
context: monaco.languages.InlineCompletionContext, token: monaco.CancellationToken): Promise<monaco.languages.InlineCompletions | undefined>
}
@injectable()
export class CodeCompletionAgentImpl implements CodeCompletionAgent {
@inject(LanguageModelService)
protected languageModelService: LanguageModelService;
async provideInlineCompletions(
model: monaco.editor.ITextModel,
position: monaco.Position,
context: monaco.languages.InlineCompletionContext,
token: monaco.CancellationToken
): Promise<monaco.languages.InlineCompletions | undefined> {
const progress = await this.progressService.showProgress(
{ text: nls.localize('theia/ai/code-completion/progressText', 'Calculating AI code completion...'), options: { location: 'window' } }
);
try {
const languageModel =
await this.languageModelRegistry.selectLanguageModel({
agent: this.id,
...this.languageModelRequirements[0],
});
if (!languageModel) {
this.logger.error(
'No language model found for code-completion-agent'
);
return undefined;
}
const variableContext: CodeCompletionVariableContext = {
model,
position,
context
};
if (token.isCancellationRequested) {
return undefined;
}
const prompt = await this.promptService
.getResolvedPromptFragment('code-completion-system', undefined, variableContext)
.then(p => p?.text);
if (!prompt) {
this.logger.error('No prompt found for code-completion-agent');
return undefined;
}
const variantInfo = this.promptService.getPromptVariantInfo('code-completion-system');
// since we do not actually hold complete conversions, the request/response pair is considered a session
const sessionId = generateUuid();
const requestId = generateUuid();
const request: UserRequest = {
messages: [{ type: 'text', actor: 'user', text: prompt }],
settings: {
stream: false
},
agentId: this.id,
sessionId,
requestId,
cancellationToken: token,
promptVariantId: variantInfo?.variantId,
isPromptVariantCustomized: variantInfo?.isCustomized
};
if (token.isCancellationRequested) {
return undefined;
}
const response = await this.languageModelService.sendRequest(languageModel, request);
if (token.isCancellationRequested) {
return undefined;
}
const completionText = await getTextOfResponse(response);
if (token.isCancellationRequested) {
return undefined;
}
const postProcessedCompletionText = this.postProcessor.postProcess(completionText);
return {
items: [{
insertText: postProcessedCompletionText,
range: new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column)
}],
enableForwardStability: true
};
} catch (e) {
if (!token.isCancellationRequested) {
console.error(e.message, e);
}
}
finally {
progress.cancel();
}
}
@inject(ILogger)
@named('code-completion-agent')
protected logger: ILogger;
@inject(LanguageModelRegistry)
protected languageModelRegistry: LanguageModelRegistry;
@inject(PromptService)
protected promptService: PromptService;
@inject(ProgressService)
protected progressService: ProgressService;
@inject(CodeCompletionPostProcessor)
protected postProcessor: CodeCompletionPostProcessor;
id = 'Code Completion';
name = 'Code Completion';
description =
nls.localize('theia/ai/completion/agent/description', 'This agent provides inline code completion in the code editor in the Theia IDE.');
prompts: PromptVariantSet[] = codeCompletionPrompts;
languageModelRequirements: LanguageModelRequirement[] = [
{
purpose: 'code-completion',
identifier: 'default/code-completion',
},
];
readonly variables: string[] = [];
readonly functions: string[] = [];
readonly agentSpecificVariables: AgentSpecificVariables[] = [
{ name: FILE.id, description: nls.localize('theia/ai/completion/agent/vars/file/description', 'The URI of the file being edited'), usedInPrompt: true },
{ name: PREFIX.id, description: nls.localize('theia/ai/completion/agent/vars/prefix/description', 'The code before the current cursor position'), usedInPrompt: true },
{ name: SUFFIX.id, description: nls.localize('theia/ai/completion/agent/vars/suffix/description', 'The code after the current cursor position'), usedInPrompt: true },
{ name: LANGUAGE.id, description: nls.localize('theia/ai/completion/agent/vars/language/description', 'The languageId of the file being edited'), usedInPrompt: true }
];
}

View File

@@ -0,0 +1,144 @@
// *****************************************************************************
// Copyright (C) 2025 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 { injectable } from '@theia/core/shared/inversify';
import * as monaco from '@theia/monaco-editor-core';
@injectable()
export class CodeCompletionCache {
private cache: Map<string, CacheEntry>;
private maxSize = 100;
constructor() {
this.cache = new Map<string, CacheEntry>();
}
/**
* Generate a unique cache key for code completion based on the file path, cursor position, and the hashed context (prefix and suffix).
* The prefix and suffix are hashed to avoid storing large or sensitive content directly in the cache key.
*
* @param filePath Path of the current file
* @param model Monaco text model of the file
* @param position Current cursor position in the editor
* @returns Unique cache key as a string
*/
generateKey(filePath: string, model: monaco.editor.ITextModel, position: monaco.Position): string {
const lineNumber = position.lineNumber;
const prefixRange = new monaco.Range(1, 1, position.lineNumber, position.column);
const prefix = model.getValueInRange(prefixRange);
const lastLine = model.getLineCount();
const lastColumn = model.getLineMaxColumn(lastLine);
const suffixRange = new monaco.Range(position.lineNumber, position.column, lastLine, lastColumn);
const suffix = model.getValueInRange(suffixRange);
const key = JSON.stringify({
filePath,
lineNumber,
prefixHash: CodeCompletionCache.hashString(prefix),
suffixHash: CodeCompletionCache.hashString(suffix)
});
return key;
}
/**
* Hash a string using a simple hash algorithm (FNV-1a 32-bit).
* This is not cryptographically secure but is sufficient for cache key uniqueness.
* @param str The string to hash
* @returns The hash as a hex string
*/
private static hashString(str: string): string {
let hash = 0x811c9dc5;
for (let i = 0; i < str.length; i++) {
hash ^= str.charCodeAt(i);
hash = (hash * 0x01000193) >>> 0;
}
return hash.toString(16);
}
/**
* Get a cached completion if available
* @param key Cache key
* @returns Cached completion or undefined
*/
get(key: string): monaco.languages.InlineCompletions | undefined {
const entry = this.cache.get(key);
if (entry) {
// Update the entry's last accessed time
entry.lastAccessed = Date.now();
return entry.value;
}
return undefined;
}
/**
* Store a completion in the cache
* @param key Cache key
* @param value Completion value to cache
*/
put(key: string, value: monaco.languages.InlineCompletions | undefined): void {
// If cache is full, remove the least recently used entry
if (this.cache.size >= this.maxSize) {
this.removeLeastRecentlyUsed();
}
this.cache.set(key, {
value,
lastAccessed: Date.now()
});
}
/**
* Clear the entire cache
*/
clear(): void {
this.cache.clear();
}
/**
* Remove the least recently used entry from the cache
*/
private removeLeastRecentlyUsed(): void {
let oldestKey: string | undefined;
let oldestTime = Infinity;
for (const [key, entry] of this.cache.entries()) {
if (entry.lastAccessed < oldestTime) {
oldestKey = key;
oldestTime = entry.lastAccessed;
}
}
if (oldestKey) {
this.cache.delete(oldestKey);
}
}
/**
* Set the maximum cache size
* @param size New maximum cache size
*/
setMaxSize(size: number): void {
this.maxSize = size;
// Trim cache if it exceeds new size
while (this.cache.size > this.maxSize) {
this.removeLeastRecentlyUsed();
}
}
}
interface CacheEntry {
value: monaco.languages.InlineCompletions | undefined;
lastAccessed: number;
}

View File

@@ -0,0 +1,35 @@
// *****************************************************************************
// Copyright (C) 2025 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 class InlineCompletionDebouncer {
private timeoutId?: number;
debounce<T>(callback: () => Promise<T>, debounceDelay: number): Promise<T> {
return new Promise<T>((resolve, reject) => {
if (this.timeoutId) {
window.clearTimeout(this.timeoutId);
}
this.timeoutId = window.setTimeout(() => {
callback()
.then(resolve)
.catch(reject);
this.timeoutId = undefined;
}, debounceDelay);
});
}
}

View File

@@ -0,0 +1,84 @@
// *****************************************************************************
// 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 { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
let disableJSDOM = enableJSDOM();
import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider';
FrontendApplicationConfigProvider.set({});
import { expect } from 'chai';
import { DefaultCodeCompletionPostProcessor } from './code-completion-postprocessor';
disableJSDOM();
describe('CodeCompletionAgentImpl', () => {
let codeCompletionProcessor: DefaultCodeCompletionPostProcessor;
before(() => {
disableJSDOM = enableJSDOM();
codeCompletionProcessor = new DefaultCodeCompletionPostProcessor();
});
after(() => {
// Disable JSDOM after all tests
disableJSDOM();
});
describe('stripBackticks', () => {
it('should remove surrounding backticks and language (TypeScript)', () => {
const input = '```TypeScript\nconsole.log(\"Hello, World!\");```';
const output = codeCompletionProcessor.stripBackticks(input);
expect(output).to.equal('console.log("Hello, World!");');
});
it('should remove surrounding backticks and language (md)', () => {
const input = '```md\nconsole.log(\"Hello, World!\");```';
const output = codeCompletionProcessor.stripBackticks(input);
expect(output).to.equal('console.log("Hello, World!");');
});
it('should remove all text after second occurrence of backticks', () => {
const input = '```js\nlet x = 10;\n```\nTrailing text should be removed';
const output = codeCompletionProcessor.stripBackticks(input);
expect(output).to.equal('let x = 10;');
});
it('should return the text unchanged if no surrounding backticks', () => {
const input = 'console.log(\"Hello, World!\");';
const output = codeCompletionProcessor.stripBackticks(input);
expect(output).to.equal('console.log("Hello, World!");');
});
it('should remove surrounding backticks without language', () => {
const input = '```\nconsole.log(\"Hello, World!\");```';
const output = codeCompletionProcessor.stripBackticks(input);
expect(output).to.equal('console.log("Hello, World!");');
});
it('should handle text starting with backticks but no second delimiter', () => {
const input = '```python\nprint(\"Hello, World!\")';
const output = codeCompletionProcessor.stripBackticks(input);
expect(output).to.equal('print("Hello, World!")');
});
it('should handle multiple internal backticks correctly', () => {
const input = '```\nFoo```Bar```FooBar```';
const output = codeCompletionProcessor.stripBackticks(input);
expect(output).to.equal('Foo```Bar```FooBar');
});
});
});

View File

@@ -0,0 +1,48 @@
// *****************************************************************************
// 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 { inject, injectable } from '@theia/core/shared/inversify';
import { PreferenceService } from '@theia/core/lib/common';
import { PREF_AI_INLINE_COMPLETION_STRIP_BACKTICKS } from '../common/ai-code-completion-preference';
export interface CodeCompletionPostProcessor {
postProcess(text: string): string;
}
export const CodeCompletionPostProcessor = Symbol('CodeCompletionPostProcessor');
@injectable()
export class DefaultCodeCompletionPostProcessor {
@inject(PreferenceService)
protected readonly preferenceService: PreferenceService;
public postProcess(text: string): string {
if (this.preferenceService.get<boolean>(PREF_AI_INLINE_COMPLETION_STRIP_BACKTICKS, true)) {
return this.stripBackticks(text);
}
return text;
}
public stripBackticks(text: string): string {
if (text.startsWith('```')) {
// Remove the first backticks and any language identifier
const startRemoved = text.slice(3).replace(/^\w*\n/, '');
const lastBacktickIndex = startRemoved.lastIndexOf('```');
return lastBacktickIndex !== -1 ? startRemoved.slice(0, lastBacktickIndex).trim() : startRemoved.trim();
}
return text;
}
}

View File

@@ -0,0 +1,81 @@
/* eslint-disable @typescript-eslint/tslint/config */
// *****************************************************************************
// Copyright (C) 2025 EclipseSource GmbH and others.
//
// This file is licensed under the MIT License.
// See LICENSE-MIT.txt in the project root for license information.
// https://opensource.org/license/mit.
//
// SPDX-License-Identifier: MIT
// *****************************************************************************
import { PromptVariantSet } from '@theia/ai-core/lib/common';
import { FILE, LANGUAGE, PREFIX, SUFFIX } from './code-completion-variables';
export const codeCompletionPrompts: PromptVariantSet[] = [{
id: 'code-completion-system',
variants: [{
id: 'code-completion-system-previous',
template: `{{!-- This prompt is licensed under the MIT License (https://opensource.org/license/mit).
Made improvements or adaptations to this prompt template? Wed love for you to share it with the community! Contribute back here:
https://github.com/eclipse-theia/theia/discussions/new?category=prompt-template-contribution --}}
You are a code completion agent. The current file you have to complete is named {{${FILE.id}}}.
The language of the file is {{${LANGUAGE.id}}}. Return your result as plain text without markdown formatting.
Finish the following code snippet.
{{${PREFIX.id}}}[[MARKER]]{{${SUFFIX.id}}}
Only return the exact replacement for [[MARKER]] to complete the snippet.`
},
{
id: 'code-completion-system-next',
template: `{{!-- This prompt is licensed under the MIT License (https://opensource.org/license/mit).
Made improvements or adaptations to this prompt template? We'd love for you to share it with the community! Contribute back here:
https://github.com/eclipse-theia/theia/discussions/new?category=prompt-template-contribution --}}
# System Role
You are an expert AI code completion assistant focused on generating precise, contextually appropriate code snippets.
## Code Context
\`\`\`
{{${PREFIX.id}}}[[MARKER]]{{${SUFFIX.id}}}
\`\`\`
## Metadata
- File: {{${FILE.id}}}
- Programming Language: {{${LANGUAGE.id}}}
- Project Context: {{prompt:project-info}}
# Completion Guidelines
1. Analyze the surrounding code context carefully.
2. Generate ONLY the code that should replace [[MARKER]].
3. Ensure the completion:
- Maintains the exact syntax of the surrounding code
- Follows best practices for the specific programming language
- Completes the code snippet logically and efficiently
4. Do NOT include any explanatory text, comments, or additional instructions.
5. Return ONLY the raw code replacement.
# Constraints
- Return strictly the code for [[MARKER]]
- Match indentation and style of surrounding code
- Prioritize readability and maintainability
- Consider language-specific idioms and patterns`
}],
defaultVariant: {
id: 'code-completion-system-default',
template: `{{!-- This prompt is licensed under the MIT License (https://opensource.org/license/mit).
Made improvements or adaptations to this prompt template? Wed love for you to share it with the community! Contribute back here:
https://github.com/eclipse-theia/theia/discussions/new?category=prompt-template-contribution --}}
## Code snippet
\`\`\`
{{${PREFIX.id}}}[[MARKER]]{{${SUFFIX.id}}}
\`\`\`
## Meta Data
- File: {{${FILE.id}}}
- Language: {{${LANGUAGE.id}}}
Replace [[MARKER]] with the exact code to complete the code snippet. Return only the replacement of [[MARKER]] as plain text.`,
},
}
];

View File

@@ -0,0 +1,30 @@
// *****************************************************************************
// Copyright (C) 2025 Lonti.com Pty Ltd.
//
// 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 { AIVariableContext } from '@theia/ai-core';
import * as monaco from '@theia/monaco-editor-core';
export interface CodeCompletionVariableContext {
model: monaco.editor.ITextModel,
position: monaco.Position,
context: monaco.languages.InlineCompletionContext
}
export namespace CodeCompletionVariableContext {
export function is(context: AIVariableContext): context is CodeCompletionVariableContext {
return !!context && 'model' in context && 'position' in context && 'context' in context;
}
}

View File

@@ -0,0 +1,160 @@
// *****************************************************************************
// Copyright (C) 2025 Lonti.com Pty Ltd.
//
// 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 { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider';
import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
let disableJSDOM = enableJSDOM();
FrontendApplicationConfigProvider.set({});
import { PreferenceService } from '@theia/core/lib/common';
import { Container } from '@theia/core/shared/inversify';
import { editor, languages, Uri } from '@theia/monaco-editor-core/esm/vs/editor/editor.api';
import { expect } from 'chai';
import * as sinon from 'sinon';
import { CodeCompletionVariableContext } from './code-completion-variable-context';
import { CodeCompletionVariableContribution } from './code-completion-variable-contribution';
import { FILE, LANGUAGE, PREFIX, SUFFIX } from './code-completion-variables';
disableJSDOM();
describe('CodeCompletionVariableContribution', () => {
let contribution: CodeCompletionVariableContribution;
let model: editor.ITextModel;
before(() => {
disableJSDOM = enableJSDOM();
const container = new Container();
container.bind(PreferenceService).toConstantValue({
get: () => 1000,
});
container.bind(CodeCompletionVariableContribution).toSelf().inSingletonScope();
contribution = container.get(CodeCompletionVariableContribution);
});
beforeEach(() => {
model = editor.createModel('//line 1\nconsole.\n//line 2', 'javascript', Uri.file('/home/user/workspace/test.js'));
sinon.stub(model, 'getLanguageId').returns('javascript');
});
afterEach(() => {
model.dispose();
});
after(() => {
// Disable JSDOM after all tests
disableJSDOM();
model.dispose();
});
describe('canResolve', () => {
it('should be able to resolve the file from the CodeCompletionVariableContext', () => {
const context: CodeCompletionVariableContext = {
model,
position: model.getPositionAt(8),
context: {
triggerKind: languages.InlineCompletionTriggerKind.Automatic,
selectedSuggestionInfo: undefined,
includeInlineEdits: false,
includeInlineCompletions: false
}
};
expect(contribution.canResolve({ variable: FILE }, context)).to.equal(1);
});
it('should not be able to resolve the file from unknown context', () => {
expect(contribution.canResolve({ variable: FILE }, {})).to.equal(0);
});
});
describe('resolve', () => {
it('should resolve the file variable', async () => {
const context: CodeCompletionVariableContext = {
model,
position: model.getPositionAt(17),
context: {
triggerKind: languages.InlineCompletionTriggerKind.Automatic,
selectedSuggestionInfo: undefined,
includeInlineEdits: false,
includeInlineCompletions: false
}
};
const resolved = await contribution.resolve({ variable: FILE }, context);
expect(resolved).to.deep.equal({
variable: FILE,
value: 'file:///home/user/workspace/test.js'
});
});
it('should resolve the language variable', async () => {
const context: CodeCompletionVariableContext = {
model,
position: model.getPositionAt(17),
context: {
triggerKind: languages.InlineCompletionTriggerKind.Automatic,
selectedSuggestionInfo: undefined,
includeInlineEdits: false,
includeInlineCompletions: false
}
};
const resolved = await contribution.resolve({ variable: LANGUAGE }, context);
expect(resolved).to.deep.equal({
variable: LANGUAGE,
value: 'javascript'
});
});
it('should resolve the prefix variable', async () => {
const context: CodeCompletionVariableContext = {
model,
position: model.getPositionAt(17),
context: {
triggerKind: languages.InlineCompletionTriggerKind.Automatic,
selectedSuggestionInfo: undefined,
includeInlineEdits: false,
includeInlineCompletions: false
}
};
const resolved = await contribution.resolve({ variable: PREFIX }, context);
expect(resolved).to.deep.equal({
variable: PREFIX,
value: '//line 1\nconsole.'
});
});
it('should resolve the suffix variable', async () => {
const context: CodeCompletionVariableContext = {
model,
position: model.getPositionAt(17),
context: {
triggerKind: languages.InlineCompletionTriggerKind.Automatic,
selectedSuggestionInfo: undefined,
includeInlineEdits: false,
includeInlineCompletions: false
}
};
const resolved = await contribution.resolve({ variable: SUFFIX }, context);
expect(resolved).to.deep.equal({
variable: SUFFIX,
value: '\n//line 2'
});
});
});
});

View File

@@ -0,0 +1,144 @@
// *****************************************************************************
// Copyright (C) 2025 Lonti.com Pty Ltd.
//
// 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 { AIVariableContext, AIVariableResolutionRequest, AIVariableResolver, ResolvedAIVariable } from '@theia/ai-core';
import { FrontendVariableContribution, FrontendVariableService } from '@theia/ai-core/lib/browser';
import { MaybePromise, PreferenceService } from '@theia/core';
import { inject, injectable } from '@theia/core/shared/inversify';
import { PREF_AI_INLINE_COMPLETION_MAX_CONTEXT_LINES } from '../common/ai-code-completion-preference';
import { CodeCompletionVariableContext } from './code-completion-variable-context';
import { FILE, LANGUAGE, PREFIX, SUFFIX } from './code-completion-variables';
@injectable()
export class CodeCompletionVariableContribution implements FrontendVariableContribution, AIVariableResolver {
@inject(PreferenceService)
protected preferences: PreferenceService;
registerVariables(service: FrontendVariableService): void {
[
FILE,
PREFIX,
SUFFIX,
LANGUAGE
].forEach(variable => {
service.registerResolver(variable, this);
});
}
canResolve(_request: AIVariableResolutionRequest, context: AIVariableContext): MaybePromise<number> {
return CodeCompletionVariableContext.is(context) ? 1 : 0;
}
async resolve(request: AIVariableResolutionRequest, context: AIVariableContext): Promise<ResolvedAIVariable | undefined> {
if (!CodeCompletionVariableContext.is(context)) {
return Promise.resolve(undefined);
}
switch (request.variable.id) {
case FILE.id:
return this.resolveFile(context);
case LANGUAGE.id:
return this.resolveLanguage(context);
case PREFIX.id:
return this.resolvePrefix(context);
case SUFFIX.id:
return this.resolveSuffix(context);
default:
return undefined;
}
}
protected resolvePrefix(context: CodeCompletionVariableContext): ResolvedAIVariable | undefined {
const position = context.position;
const model = context.model;
const maxContextLines = this.preferences.get<number>(PREF_AI_INLINE_COMPLETION_MAX_CONTEXT_LINES, -1);
let prefixStartLine = 1;
if (maxContextLines === 0) {
// Only the cursor line
prefixStartLine = position.lineNumber;
} else if (maxContextLines > 0) {
const linesBeforeCursor = position.lineNumber - 1;
// Allocate one more line to the prefix in case of an odd maxContextLines
const prefixLines = Math.min(
Math.ceil(maxContextLines / 2),
linesBeforeCursor
);
prefixStartLine = Math.max(1, position.lineNumber - prefixLines);
}
const prefix = model.getValueInRange({
startLineNumber: prefixStartLine,
startColumn: 1,
endLineNumber: position.lineNumber,
endColumn: position.column,
});
return {
variable: PREFIX,
value: prefix
};
}
protected resolveSuffix(context: CodeCompletionVariableContext): ResolvedAIVariable | undefined {
const position = context.position;
const model = context.model;
const maxContextLines = this.preferences.get<number>(PREF_AI_INLINE_COMPLETION_MAX_CONTEXT_LINES, -1);
let suffixEndLine = model.getLineCount();
if (maxContextLines === 0) {
suffixEndLine = position.lineNumber;
} else if (maxContextLines > 0) {
const linesAfterCursor = model.getLineCount() - position.lineNumber;
const suffixLines = Math.min(
Math.floor(maxContextLines / 2),
linesAfterCursor
);
suffixEndLine = Math.min(model.getLineCount(), position.lineNumber + suffixLines);
}
const suffix = model.getValueInRange({
startLineNumber: position.lineNumber,
startColumn: position.column,
endLineNumber: suffixEndLine,
endColumn: model.getLineMaxColumn(suffixEndLine),
});
return {
variable: SUFFIX,
value: suffix
};
}
protected resolveLanguage(context: CodeCompletionVariableContext): ResolvedAIVariable | undefined {
return {
variable: LANGUAGE,
value: context.model.getLanguageId()
};
}
protected resolveFile(context: CodeCompletionVariableContext): ResolvedAIVariable | undefined {
return {
variable: FILE,
value: context.model.uri.toString(false)
};
}
}

View File

@@ -0,0 +1,42 @@
// *****************************************************************************
// Copyright (C) 2025 Lonti.com Pty Ltd.
//
// 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 { AIVariable } from '@theia/ai-core/lib/common/variable-service';
import { nls } from '@theia/core';
export const FILE: AIVariable = {
id: 'codeCompletionFile',
name: 'codeCompletionFile',
description: nls.localize('theia/ai/completion/fileVariable/description', 'The URI of the file being edited. Only available in code completion context.'),
};
export const PREFIX: AIVariable = {
id: 'codeCompletionPrefix',
name: 'codeCompletionPrefix',
description: nls.localize('theia/ai/completion/prefixVariable/description', 'The code before the current cursor position. Only available in code completion context.'),
};
export const SUFFIX: AIVariable = {
id: 'codeCompletionSuffix',
name: 'codeCompletionSuffix',
description: nls.localize('theia/ai/completion/suffixVariable/description', 'The code after the current cursor position. Only available in code completion context.'),
};
export const LANGUAGE: AIVariable = {
id: 'codeCompletionLanguage',
name: 'codeCompletionLanguage',
description: nls.localize('theia/ai/completion/languageVariable/description', 'The languageId of the file being edited. Only available in code completion context.'),
};

View File

@@ -0,0 +1,82 @@
// *****************************************************************************
// 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 PREF_AI_INLINE_COMPLETION_AUTOMATIC_ENABLE = 'ai-features.codeCompletion.automaticCodeCompletion';
export const PREF_AI_INLINE_COMPLETION_DEBOUNCE_DELAY = 'ai-features.codeCompletion.debounceDelay';
export const PREF_AI_INLINE_COMPLETION_EXCLUDED_EXTENSIONS = 'ai-features.codeCompletion.excludedFileExtensions';
export const PREF_AI_INLINE_COMPLETION_MAX_CONTEXT_LINES = 'ai-features.codeCompletion.maxContextLines';
export const PREF_AI_INLINE_COMPLETION_STRIP_BACKTICKS = 'ai-features.codeCompletion.stripBackticks';
export const PREF_AI_INLINE_COMPLETION_CACHE_CAPACITY = 'ai-features.codeCompletion.cacheCapacity';
export const AICodeCompletionPreferencesSchema: PreferenceSchema = {
properties: {
[PREF_AI_INLINE_COMPLETION_AUTOMATIC_ENABLE]: {
title: AI_CORE_PREFERENCES_TITLE,
type: 'boolean',
description: nls.localize('theia/ai/completion/automaticEnable/description',
'Automatically trigger AI completions inline within any (Monaco) editor while editing.\
\n\
Alternatively, you can manually trigger the code via the command "Trigger Inline Suggestion" or the default shortcut "Ctrl+Alt+Space".'),
default: false
},
[PREF_AI_INLINE_COMPLETION_DEBOUNCE_DELAY]: {
title: nls.localize('theia/ai/completion/debounceDelay/title', 'Debounce Delay'),
type: 'number',
description: nls.localize('theia/ai/completion/debounceDelay/description',
'Controls the delay in milliseconds before triggering AI completions after changes have been detected in the editor.\
Requires `Automatic Code Completion` to be enabled. Enter 0 to disable the debounce delay.'),
default: 300
},
[PREF_AI_INLINE_COMPLETION_EXCLUDED_EXTENSIONS]: {
title: nls.localize('theia/ai/completion/excludedFileExts/title', 'Excluded File Extensions'),
type: 'array',
description: nls.localize('theia/ai/completion/excludedFileExts/description', 'Specify file extensions (e.g., .md, .txt) where AI completions should be disabled.'),
items: {
type: 'string'
},
default: []
},
[PREF_AI_INLINE_COMPLETION_MAX_CONTEXT_LINES]: {
title: nls.localize('theia/ai/completion/maxContextLines/title', 'Maximum Context Lines'),
type: 'number',
description: nls.localize('theia/ai/completion/maxContextLines/description',
'The maximum number of lines used as context, distributed among the lines before and after the cursor position (prefix and suffix).\
Set this to -1 to use the full file as context without any line limit and 0 to only use the current line.'),
default: -1,
minimum: -1
},
[PREF_AI_INLINE_COMPLETION_STRIP_BACKTICKS]: {
title: nls.localize('theia/ai/completion/stripBackticks/title', 'Strip Backticks from Inline Completions'),
type: 'boolean',
description: nls.localize('theia/ai/completion/stripBackticks/description',
'Remove surrounding backticks from the code returned by some LLMs. If a backtick is detected, all content after the closing\
backtick is stripped as well. This setting helps ensure plain code is returned when language models use markdown-like formatting.'),
default: true
},
[PREF_AI_INLINE_COMPLETION_CACHE_CAPACITY]: {
title: nls.localize('theia/ai/completion/cacheCapacity/title', 'Code Completion Cache Capacity'),
type: 'number',
description: nls.localize('theia/ai/completion/cacheCapacity/description',
'Maximum number of code completions to store in the cache. A higher number can improve performance but will consume more memory.\
Minimum value is 10, recommended range is between 50-200.'),
default: 100,
minimum: 10
}
}
};

View File

@@ -0,0 +1,23 @@
// *****************************************************************************
// Copyright (C) 2025 STMicroelectronics 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
// *****************************************************************************
import { PreferenceContribution } from '@theia/core';
import { ContainerModule } from '@theia/core/shared/inversify';
import { AICodeCompletionPreferencesSchema } from '../common/ai-code-completion-preference';
export default new ContainerModule(bind => {
bind(PreferenceContribution).toConstantValue({ schema: AICodeCompletionPreferencesSchema });
});

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-code-completion package', () => {
it('support code coverage statistics', () => true);
});

View File

@@ -0,0 +1,28 @@
{
"extends": "../../configs/base.tsconfig",
"compilerOptions": {
"composite": true,
"rootDir": "src",
"outDir": "lib"
},
"include": [
"src"
],
"references": [
{
"path": "../ai-core"
},
{
"path": "../core"
},
{
"path": "../filesystem"
},
{
"path": "../output"
},
{
"path": "../workspace"
}
]
}