From ee0b960cff754e6ada9cb113a9e9cde966ee29f8 Mon Sep 17 00:00:00 2001 From: Camille Letavernier Date: Fri, 3 Jul 2026 10:14:58 +0200 Subject: [PATCH 1/3] feat: reference open editors in Architect, Coder and Universal system prompts --- .../src/browser/architect-prompt-template.ts | 7 ++++ .../ai-ide/src/browser/frontend-module.ts | 2 + .../browser/open-editors-prompt-fragment.ts | 40 +++++++++++++++++++ .../common/coder-replace-prompt-template.ts | 7 ++++ .../common/open-editors-hint-fragment-id.ts | 17 ++++++++ .../src/common/universal-prompt-template.ts | 3 ++ 6 files changed, 76 insertions(+) create mode 100644 packages/ai-ide/src/browser/open-editors-prompt-fragment.ts create mode 100644 packages/ai-ide/src/common/open-editors-hint-fragment-id.ts diff --git a/packages/ai-ide/src/browser/architect-prompt-template.ts b/packages/ai-ide/src/browser/architect-prompt-template.ts index fce6b35643260..87bec35bf4a4b 100644 --- a/packages/ai-ide/src/browser/architect-prompt-template.ts +++ b/packages/ai-ide/src/browser/architect-prompt-template.ts @@ -19,6 +19,7 @@ import { GET_WORKSPACE_FILE_LIST_FUNCTION_ID, FILE_CONTENT_FUNCTION_ID, SEARCH_IN_WORKSPACE_FUNCTION_ID, FIND_FILES_BY_PATTERN_FUNCTION_ID } from '../common/workspace-functions'; import { CONTEXT_FILES_VARIABLE_ID, TASK_CONTEXT_SUMMARY_VARIABLE_ID } from '../common/context-variables'; +import { OPEN_EDITORS_HINT_FRAGMENT_ID } from '../common/open-editors-hint-fragment-id'; import { CREATE_TASK_CONTEXT_FUNCTION_ID, GET_TASK_CONTEXT_FUNCTION_ID, @@ -194,6 +195,8 @@ When a diagram clarifies an architectural concept or how something is implemente {{prompt:project-info}} +{{prompt:${OPEN_EDITORS_HINT_FRAGMENT_ID}}} + {{${TASK_CONTEXT_SUMMARY_VARIABLE_ID}}} ` }, @@ -231,6 +234,8 @@ Always look at the relevant files to understand your task using the function ~{$ {{${CONTEXT_FILES_VARIABLE_ID}}} {{prompt:project-info}} + +{{prompt:${OPEN_EDITORS_HINT_FRAGMENT_ID}}} ` }, { @@ -464,6 +469,8 @@ When a diagram clarifies an architectural concept or how something is implemente {{prompt:project-info}} +{{prompt:${OPEN_EDITORS_HINT_FRAGMENT_ID}}} + {{${TASK_CONTEXT_SUMMARY_VARIABLE_ID}}} ` }] diff --git a/packages/ai-ide/src/browser/frontend-module.ts b/packages/ai-ide/src/browser/frontend-module.ts index 275fbdd97ac78..e82810a588f57 100644 --- a/packages/ai-ide/src/browser/frontend-module.ts +++ b/packages/ai-ide/src/browser/frontend-module.ts @@ -119,6 +119,7 @@ import { AddressGhReviewCommandContribution } from './address-pr-review-command- import { AppTesterCapabilityContribution } from './apptester-capability-contribution'; import { GitHubCapabilityContribution } from './github-capability-contribution'; import { ShellExecutionCapabilityContribution } from './shell-execution-capability-contribution'; +import { OpenEditorsHintContribution } from './open-editors-prompt-fragment'; import { AgentModeConfirmationService, AgentModeConfirmationServiceImpl } from './agent-mode-confirmation-service'; import { ExploreAgent } from './explore-agent'; import { CodeReviewerAgent } from './code-reviewer-agent'; @@ -347,6 +348,7 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => { bind(FrontendApplicationContribution).to(AppTesterCapabilityContribution); bind(FrontendApplicationContribution).to(GitHubCapabilityContribution); bind(FrontendApplicationContribution).to(ShellExecutionCapabilityContribution); + bind(FrontendApplicationContribution).to(OpenEditorsHintContribution); bind(FrontendApplicationContribution).to(CodeReviewCapabilityContribution); bind(FrontendApplicationContribution).to(PRReviewCapabilityContribution); diff --git a/packages/ai-ide/src/browser/open-editors-prompt-fragment.ts b/packages/ai-ide/src/browser/open-editors-prompt-fragment.ts new file mode 100644 index 0000000000000..c6ceb647ffd92 --- /dev/null +++ b/packages/ai-ide/src/browser/open-editors-prompt-fragment.ts @@ -0,0 +1,40 @@ +// ***************************************************************************** +// Copyright (C) 2026 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 { PromptService } from '@theia/ai-core/lib/common'; +import { OPEN_EDITORS_HINT_FRAGMENT_ID } from '../common/open-editors-hint-fragment-id'; + +export { OPEN_EDITORS_HINT_FRAGMENT_ID }; + +@injectable() +export class OpenEditorsHintContribution implements FrontendApplicationContribution { + + @inject(PromptService) + protected readonly promptService: PromptService; + + onStart(): void { + this.promptService.addBuiltInPromptFragment({ + id: OPEN_EDITORS_HINT_FRAGMENT_ID, + template: `## Open Editors +The following files are currently open in the user's editor. This is provided as contextual information only \ +— these files may or may not be relevant to the current request. Do not assume they are related unless the user explicitly refers to them. + +{{openEditors}}` + }); + } +} diff --git a/packages/ai-ide/src/common/coder-replace-prompt-template.ts b/packages/ai-ide/src/common/coder-replace-prompt-template.ts index f1b9e6dac18bf..6116fc2864001 100644 --- a/packages/ai-ide/src/common/coder-replace-prompt-template.ts +++ b/packages/ai-ide/src/common/coder-replace-prompt-template.ts @@ -36,6 +36,7 @@ import { } from './file-changeset-function-ids'; import { GET_TASK_CONTEXT_FUNCTION_ID } from './task-context-function-ids'; import { ArchitectAgentId, ExploreAgentId } from './agent-ids'; +import { OPEN_EDITORS_HINT_FRAGMENT_ID } from './open-editors-hint-fragment-id'; export const CODER_SYSTEM_PROMPT_ID = 'coder-system'; @@ -259,6 +260,8 @@ Always retrieve relevant files using ~{${FILE_CONTENT_FUNCTION_ID}} to understan ## Project Info {{prompt:project-info}} +{{prompt:${OPEN_EDITORS_HINT_FRAGMENT_ID}}} + {{${TASK_CONTEXT_SUMMARY_VARIABLE_ID}}} # Final Instruction @@ -549,6 +552,8 @@ Always retrieve relevant files using ~{${FILE_CONTENT_FUNCTION_ID}} to understan ## Project Info {{prompt:project-info}} +{{prompt:${OPEN_EDITORS_HINT_FRAGMENT_ID}}} + {{${TASK_CONTEXT_SUMMARY_VARIABLE_ID}}} # Final Instruction @@ -639,6 +644,8 @@ You have previously proposed changes for the following files. Some suggestions m {{prompt:project-info}} +{{prompt:${OPEN_EDITORS_HINT_FRAGMENT_ID}}} + {{${TASK_CONTEXT_SUMMARY_VARIABLE_ID}}} ## Final Instruction diff --git a/packages/ai-ide/src/common/open-editors-hint-fragment-id.ts b/packages/ai-ide/src/common/open-editors-hint-fragment-id.ts new file mode 100644 index 0000000000000..9a9bdb59b04a7 --- /dev/null +++ b/packages/ai-ide/src/common/open-editors-hint-fragment-id.ts @@ -0,0 +1,17 @@ +// ***************************************************************************** +// Copyright (C) 2026 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 OPEN_EDITORS_HINT_FRAGMENT_ID = 'open-editors-hint'; diff --git a/packages/ai-ide/src/common/universal-prompt-template.ts b/packages/ai-ide/src/common/universal-prompt-template.ts index 3bbfcf6858f58..9d4010193f1fc 100644 --- a/packages/ai-ide/src/common/universal-prompt-template.ts +++ b/packages/ai-ide/src/common/universal-prompt-template.ts @@ -11,6 +11,7 @@ import { BasePromptFragment } from '@theia/ai-core/lib/common'; import { CHAT_CONTEXT_DETAILS_VARIABLE_ID } from '@theia/ai-chat'; +import { OPEN_EDITORS_HINT_FRAGMENT_ID } from './open-editors-hint-fragment-id'; export const universalTemplate: BasePromptFragment = { id: 'universal-system-default', @@ -23,6 +24,8 @@ You are an assistant integrated into {{productName}}, designed to assist softwar ## Current Context Some files and other pieces of data may have been added by the user to the context of the chat. If any have, the details can be found below. {{${CHAT_CONTEXT_DETAILS_VARIABLE_ID}}} + +{{prompt:${OPEN_EDITORS_HINT_FRAGMENT_ID}}} ` }; From 6c9298df395995c41584ec515704f385ea93f8de Mon Sep 17 00:00:00 2001 From: Camille Letavernier Date: Fri, 3 Jul 2026 11:29:37 +0200 Subject: [PATCH 2/3] feat: automatically add open files to the context --- .../ai-ide/src/browser/frontend-module.ts | 2 + .../open-editors-context-contribution.ts | 81 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 packages/ai-ide/src/browser/open-editors-context-contribution.ts diff --git a/packages/ai-ide/src/browser/frontend-module.ts b/packages/ai-ide/src/browser/frontend-module.ts index e82810a588f57..8c423d70544b8 100644 --- a/packages/ai-ide/src/browser/frontend-module.ts +++ b/packages/ai-ide/src/browser/frontend-module.ts @@ -120,6 +120,7 @@ import { AppTesterCapabilityContribution } from './apptester-capability-contribu import { GitHubCapabilityContribution } from './github-capability-contribution'; import { ShellExecutionCapabilityContribution } from './shell-execution-capability-contribution'; import { OpenEditorsHintContribution } from './open-editors-prompt-fragment'; +import { OpenEditorsContextContribution } from './open-editors-context-contribution'; import { AgentModeConfirmationService, AgentModeConfirmationServiceImpl } from './agent-mode-confirmation-service'; import { ExploreAgent } from './explore-agent'; import { CodeReviewerAgent } from './code-reviewer-agent'; @@ -349,6 +350,7 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => { bind(FrontendApplicationContribution).to(GitHubCapabilityContribution); bind(FrontendApplicationContribution).to(ShellExecutionCapabilityContribution); bind(FrontendApplicationContribution).to(OpenEditorsHintContribution); + bind(FrontendApplicationContribution).to(OpenEditorsContextContribution); bind(FrontendApplicationContribution).to(CodeReviewCapabilityContribution); bind(FrontendApplicationContribution).to(PRReviewCapabilityContribution); diff --git a/packages/ai-ide/src/browser/open-editors-context-contribution.ts b/packages/ai-ide/src/browser/open-editors-context-contribution.ts new file mode 100644 index 0000000000000..3463f89c080a4 --- /dev/null +++ b/packages/ai-ide/src/browser/open-editors-context-contribution.ts @@ -0,0 +1,81 @@ +// ***************************************************************************** +// Copyright (C) 2026 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 +// ***************************************************************************** + +import { FrontendApplicationContribution } from '@theia/core/lib/browser'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import URI from '@theia/core/lib/common/uri'; +import { FILE_VARIABLE } from '@theia/ai-core/lib/browser/file-variable-contribution'; +import { ChatContextManager, ChatService, isSessionCreatedEvent } from '@theia/ai-chat/lib/common'; +import { EditorManager } from '@theia/editor/lib/browser'; +import { WorkspaceService } from '@theia/workspace/lib/browser'; + +/** + * Automatically populates the active chat session's context with open editor files. + * + * When a new chat session is created, all currently open workspace editors are added + * as file context variables. When a new editor is opened while an active session exists, + * that file is added to the session's context as well. Files outside the workspace are + * ignored, and duplicates are prevented by the existing deduplication in {@link ChatContextManager.addVariables}. + * + * The added files appear as removable context pills in the chat input UI, allowing + * users to discard irrelevant files before sending a message. + */ +@injectable() +export class OpenEditorsContextContribution implements FrontendApplicationContribution { + @inject(ChatService) + protected readonly chatService: ChatService; + + @inject(EditorManager) + protected readonly editorManager: EditorManager; + + @inject(WorkspaceService) + protected readonly workspaceService: WorkspaceService; + + onStart(): void { + this.chatService.onSessionEvent(event => { + if (isSessionCreatedEvent(event)) { + const activeSession = this.chatService.getActiveSession(); + if (activeSession && activeSession.id === event.sessionId) { + for (const editor of this.editorManager.all) { + const uri = editor.getResourceUri(); + if (uri) { + this.addFileToContext(uri, activeSession.model.context); + } + } + } + } + }); + + this.editorManager.onCreated(widget => { + const uri = widget.getResourceUri(); + if (uri) { + const activeSession = this.chatService.getActiveSession(); + if (activeSession) { + this.addFileToContext(uri, activeSession.model.context); + } + } + }); + } + + protected addFileToContext(uri: URI, context: ChatContextManager): void { + const rootUri = this.workspaceService.getWorkspaceRootUri(uri); + if (!rootUri) { + return; + } + const relativePath = this.workspaceService.getRootPrefixedPath(uri); + context.addVariables({ variable: FILE_VARIABLE, arg: relativePath }); + } +} From 1f21b261eeff8a300bc327f74a8ce3c1516e9647 Mon Sep 17 00:00:00 2001 From: Camille Letavernier Date: Fri, 3 Jul 2026 12:54:34 +0200 Subject: [PATCH 3/3] feat: add a preference to add open editors to the context --- .../browser/open-editors-context-contribution.ts | 15 +++++++++++++++ packages/ai-ide/src/common/ai-ide-preferences.ts | 10 ++++++++++ 2 files changed, 25 insertions(+) diff --git a/packages/ai-ide/src/browser/open-editors-context-contribution.ts b/packages/ai-ide/src/browser/open-editors-context-contribution.ts index 3463f89c080a4..4398b10b69306 100644 --- a/packages/ai-ide/src/browser/open-editors-context-contribution.ts +++ b/packages/ai-ide/src/browser/open-editors-context-contribution.ts @@ -15,7 +15,9 @@ // ***************************************************************************** import { FrontendApplicationContribution } from '@theia/core/lib/browser'; +import { PreferenceService } from '@theia/core'; import { inject, injectable } from '@theia/core/shared/inversify'; +import { PREFERENCE_NAME_AUTO_ADD_OPEN_EDITORS } from '../common/ai-ide-preferences'; import URI from '@theia/core/lib/common/uri'; import { FILE_VARIABLE } from '@theia/ai-core/lib/browser/file-variable-contribution'; import { ChatContextManager, ChatService, isSessionCreatedEvent } from '@theia/ai-chat/lib/common'; @@ -44,9 +46,19 @@ export class OpenEditorsContextContribution implements FrontendApplicationContri @inject(WorkspaceService) protected readonly workspaceService: WorkspaceService; + @inject(PreferenceService) + protected readonly preferenceService: PreferenceService; + + protected get isEnabled(): boolean { + return this.preferenceService.get(PREFERENCE_NAME_AUTO_ADD_OPEN_EDITORS, true); + } + onStart(): void { this.chatService.onSessionEvent(event => { if (isSessionCreatedEvent(event)) { + if (!this.isEnabled) { + return; + } const activeSession = this.chatService.getActiveSession(); if (activeSession && activeSession.id === event.sessionId) { for (const editor of this.editorManager.all) { @@ -60,6 +72,9 @@ export class OpenEditorsContextContribution implements FrontendApplicationContri }); this.editorManager.onCreated(widget => { + if (!this.isEnabled) { + return; + } const uri = widget.getResourceUri(); if (uri) { const activeSession = this.chatService.getActiveSession(); diff --git a/packages/ai-ide/src/common/ai-ide-preferences.ts b/packages/ai-ide/src/common/ai-ide-preferences.ts index 89bf883bdfe9d..2a26250982260 100644 --- a/packages/ai-ide/src/common/ai-ide-preferences.ts +++ b/packages/ai-ide/src/common/ai-ide-preferences.ts @@ -21,6 +21,7 @@ import { nls, PreferenceSchema, PreferenceScope } from '@theia/core'; export const PREFERENCE_NAME_ENABLE_AI = 'ai-features.AiEnable.enableAI'; export const PREFERENCE_NAME_ORCHESTRATOR_EXCLUSION_LIST = 'ai-features.orchestrator.excludedAgents'; export const PREFERENCE_NAME_AGENT_MODE_ENABLED = 'ai-features.agentMode.enabled'; +export const PREFERENCE_NAME_AUTO_ADD_OPEN_EDITORS = 'ai-features.chat.autoAddOpenEditors'; export const aiIdePreferenceSchema: PreferenceSchema = { properties: { [PREFERENCE_NAME_ENABLE_AI]: { @@ -57,6 +58,15 @@ export const aiIdePreferenceSchema: PreferenceSchema = { type: 'boolean', default: false, scope: PreferenceScope.User + }, + [PREFERENCE_NAME_AUTO_ADD_OPEN_EDITORS]: { + title: AI_CORE_PREFERENCES_TITLE, + description: nls.localize('theia/ai/ide/autoAddOpenEditors/description', + 'Automatically add open editor files to the chat context. ' + + 'When enabled, all open editors are added to new chat sessions, ' + + 'and newly opened files are added to the active session.'), + type: 'boolean', + default: true, } } };