From 42226829b92333e25fc6ece7ab15683810fd88e6 Mon Sep 17 00:00:00 2001 From: Philip Langer Date: Fri, 21 Feb 2025 17:31:35 +0100 Subject: [PATCH 1/3] doc: add chat context documentation --- src/docs/theia_ai.md | 176 ++++++++++++++++++++++++++++++++++- src/docs/user_ai.md | 7 +- static/context-variables.png | Bin 0 -> 40239 bytes 3 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 static/context-variables.png diff --git a/src/docs/theia_ai.md b/src/docs/theia_ai.md index 35eb110..dd65ca4 100644 --- a/src/docs/theia_ai.md +++ b/src/docs/theia_ai.md @@ -21,6 +21,7 @@ High Level Architecture of Theia AI - [Variables](#variables) - [Agent-specific Variables](#agent-specific-variables) - [Global Variables](#global-variables) + - [Chat Context Variables](#chat-context-variables) - [Tool Functions](#tool-functions) - [Custom Response Part Rendering](#custom-response-part-rendering) - [Managing the State of a Chat Response](#managing-the-state-of-a-chat-response) @@ -217,7 +218,180 @@ export class TodayVariableContribution implements AIVariableContribution, AIVari bind(AIVariableContribution).to(TodayVariableContribution).inSingletonScope(); ``` -It can now be used in any prompt template, as well as in user requests. +### Chat Context Variables + +Theia AI supports attaching rich contextual information to chat requests via **context variables**. Unlike standard variables discussed above, which simply inject a value into the prompt, context variables provide both a `value` and a `contextValue`. The `value` is inserted at the position of the variable usage, while the `contextValue` is added to the `ChatRequestModel.context`—supplying additional data that the chat agent and underlying LLM can leverage for more informed responses. + +Context variables enable users to scope their requests by including elements such as files, symbols, or other domain-specific data elements. +It is up to the agent to decide how this additional data is processed. Common processing approaches include: + +1. **Summarization:** The agent may summarize the provided context (e.g., listing file names) before passing it to the LLM. +2. **Context Window Management:** The agent may decide how much context to include the entire context if it fits, apply ranking/summarization if too large, or use multi-turn prompt flows to incrementally identify relevant parts and refine the provided context. +3. **On-Demand Retrieval:** Instead of sending all context upfront, the agent may also expose tool functions so that the LLM can fetch specific elements when needed. + +#### Usage + +Users can attach context elements to chat requests in several ways: + +- **Drag and Drop:** Drag elements into the chat input, e.g. dropping files from the file explorer. +- **Typing:** Enter the context variable name (e.g. `#file`), which triggers a quick pick selection dialog. +- **Auto-completion:** Type and select a specific element (e.g. `#file:myFile.txt`). + +Attach Files to the Context + +Once attached, the context elements are displayed in the chat input to the user. + +##### Implementation Example: File Context Variable + +The following code registers a file context variable provider along with its label provider: + +```ts +export default new ContainerModule(bind => { + ... + // the plain variable registration + bind(AIVariableContribution).to(FileVariableContribution).inSingletonScope(); + // the registration of the additional support contributions, such as the drag-and-drop handler, auto-completion, etc. + bind(AIVariableContribution).to(FileChatVariableContribution).inSingletonScope(); + // the label provider controlling how the context element is displayed in the chat input + bind(ContextFileVariableLabelProvider).toSelf().inSingletonScope(); + bind(LabelProviderContribution).toService(ContextFileVariableLabelProvider); + ... +}); +``` + +#### File Variable Provider + +This provider resolves a file variable by reading the contents of the specified file. Note the difference: it returns a `value` (e.g., a workspace-relative file path) which will be inserted in to the user request when `#file:abc.txt` is used, and a `contextValue` (the file’s actual content) for further processing of the agent. + +```ts +export const FILE_VARIABLE: AIVariable = { + id: 'file-provider', + description: 'Resolves the path and the contents of a file', + name: 'file', + label: 'File', + // specifies the icon to be used in the user interface for selecting this variable type + iconClasses: codiconArray('file'), + // sets this variable as a context variable + isContextVariable: true, + // specifying the arguments this variable takes (the URI of the file) + args: [{ name: 'uri', description: 'The URI of the requested file.' }] +}; + +@injectable() +export class FileVariableContribution implements AIVariableContribution, AIVariableResolver { + @inject(FileService) + protected readonly fileService: FileService; + + @inject(WorkspaceService) + protected readonly wsService: WorkspaceService; + + registerVariables(service: AIVariableService): void { + service.registerResolver(FILE_VARIABLE, this); + } + + async canResolve(request: AIVariableResolutionRequest, _: AIVariableContext): Promise { + return request.variable.name === FILE_VARIABLE.name ? 1 : 0; + } + + async resolve(request: AIVariableResolutionRequest, _: AIVariableContext): Promise { + //... + try { + const content = await this.fileService.readFile(path); + return { + variable: request.variable, + value: await this.wsService.getWorkspaceRelativePath(path), + contextValue: content.value.toString(), + }; + } catch (error) { + return undefined; + } + } + //... +} +``` + +#### File Chat Variable Contributions + +To enhance usability, additional contributions are implemented to handle argument picking, auto-completion, and drag-and-drop support for file context variables. + +```ts +export class FileChatVariableContribution implements FrontendVariableContribution { + @inject(FileService) + protected readonly fileService: FileService; + + @inject(WorkspaceService) + protected readonly wsService: WorkspaceService; + + @inject(QuickInputService) + protected readonly quickInputService: QuickInputService; + + @inject(QuickFileSelectService) + protected readonly quickFileSelectService: QuickFileSelectService; + + registerVariables(service: FrontendVariableService): void { + service.registerArgumentPicker(FILE_VARIABLE, this.triggerArgumentPicker.bind(this)); + service.registerArgumentCompletionProvider(FILE_VARIABLE, this.provideArgumentCompletionItems.bind(this)); + service.registerDropHandler(this.handleDrop.bind(this)); + } + + protected async triggerArgumentPicker(): Promise { + // triggered when the user auto-completes the variable name in the chat input, e.g. #file + // below we use the quick input service to show a file picker + const quickPick = this.quickInputService.createQuickPick(); + quickPick.items = await this.quickFileSelectService.getPicks(); + + const updateItems = async (value: string) => { + quickPick.items = await this.quickFileSelectService.getPicks(value, CancellationToken.None); + }; + + const onChangeListener = quickPick.onDidChangeValue(updateItems); + quickPick.show(); + + return new Promise(resolve => { + quickPick.onDispose(onChangeListener.dispose); + quickPick.onDidAccept(async () => { + const selectedItem = quickPick.selectedItems[0]; + if (selectedItem && FileQuickPickItem.is(selectedItem)) { + quickPick.dispose(); + resolve(await this.wsService.getWorkspaceRelativePath(selectedItem.uri)); + } + }); + }); + } + + protected async provideArgumentCompletionItems( + model: monaco.editor.ITextModel, + position: monaco.Position + ): Promise { + // triggered when the user auto-completes after `#` or `#:` + // your implementation needs to return a list of completion items + //... + } + + protected async handleDrop(event: DragEvent, _: AIVariableContext): Promise { + // triggered when the user drags an element into the chat input + // your implementation needs to read the `event.dataTransfer` and return a variable to add to the request + // and optionally a text to add to the chat input + const data = event.dataTransfer?.getData('selected-tree-nodes'); + if (!data) { + return undefined; + } + + try { + //... + return { variables, text }; + } catch { + return undefined; + } + } +} +``` + +#### Using the Context Variables from Agents + +Your custom agent can now use the context variables in various ways. The context variables are available in the `context` property of the `ChatRequestModel` and apply your custom logic to decide in which way your agent passes the context data to the LLM. + +Your agents can use the variables `#contextSummary` or `#contextDetails`, which resolve to either a list or the full context, in your system message to transfer the attached context to the LLM. Alternatively, you can use the tool functions `~{context_ListChatContext}` and `~{context_ResolveChatContext}` to allow the LLM obtaining the context on demand. ### Tool Functions diff --git a/src/docs/user_ai.md b/src/docs/user_ai.md index fcd4275..a753bcc 100644 --- a/src/docs/user_ai.md +++ b/src/docs/user_ai.md @@ -279,7 +279,12 @@ The Theia IDE provides a global chat interface where users can interact with all General AI Chat in the Theia IDE -Some agents produce special results, such as buttons (shown in the screenshot above) or code that can be directly inserted. You can augment your requests in the chat with context by using variables. For example, to refer to the currently selected text, use `#selectedText` in your request. Pressing '#' in the chat will show a list of available variables. +Some agents produce special results, such as buttons (shown in the screenshot above) or code that can be directly inserted. You can augment your requests in the chat with context by using variables. For example, to refer to the currently selected text, use `#selectedText` in your request. Pressing '#' in ^the chat will show a list of available variables. + +You can also pass context files into the chat to further specify the scope of your request. To do this, drag and drop a file into the chat view, or use the auto-completion feature by typing `#file` or directly typing `#`. +Note that the use of the variable `#file:src/my-code.ts` in the chat input text will resolve to the workspace-relative path, while attaching the file into the context, makes the contents available to the chat agent. This allows adding the file content and then referring to it in the chat input text conveniently. + +Attach Files to the Context ## AI Configuration diff --git a/static/context-variables.png b/static/context-variables.png new file mode 100644 index 0000000000000000000000000000000000000000..ee021b88af86fe0f57f8a6668ef49212fe7bed1f GIT binary patch literal 40239 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 a-v5_(@^8)-w_exI00f?{elF{r5}E+?M$^Oq literal 0 HcmV?d00001 From 4fac4cde5eb3a69b8e538715a7472a4d71864771 Mon Sep 17 00:00:00 2001 From: Philip Langer Date: Thu, 27 Feb 2025 12:47:26 +0100 Subject: [PATCH 2/3] Address review feedback --- src/docs/theia_ai.md | 15 +++++++++++++-- src/docs/user_ai.md | 6 ++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/docs/theia_ai.md b/src/docs/theia_ai.md index dd65ca4..24ebd17 100644 --- a/src/docs/theia_ai.md +++ b/src/docs/theia_ai.md @@ -218,6 +218,8 @@ export class TodayVariableContribution implements AIVariableContribution, AIVari bind(AIVariableContribution).to(TodayVariableContribution).inSingletonScope(); ``` +It can now be used in any prompt template, as well as in user requests. + ### Chat Context Variables Theia AI supports attaching rich contextual information to chat requests via **context variables**. Unlike standard variables discussed above, which simply inject a value into the prompt, context variables provide both a `value` and a `contextValue`. The `value` is inserted at the position of the variable usage, while the `contextValue` is added to the `ChatRequestModel.context`—supplying additional data that the chat agent and underlying LLM can leverage for more informed responses. @@ -229,6 +231,15 @@ It is up to the agent to decide how this additional data is processed. Common pr 2. **Context Window Management:** The agent may decide how much context to include the entire context if it fits, apply ranking/summarization if too large, or use multi-turn prompt flows to incrementally identify relevant parts and refine the provided context. 3. **On-Demand Retrieval:** Instead of sending all context upfront, the agent may also expose tool functions so that the LLM can fetch specific elements when needed. +Note that the context feature is enabled by default, but can be disabled by rebinding the `AIChatInputConfiguration` in your custom dependency injection module: + +```ts +rebind(AIChatInputConfiguration).toConstantValue({ + showContext: false, + showPinnedAgent: true +}); +``` + #### Usage Users can attach context elements to chat requests in several ways: @@ -312,7 +323,7 @@ export class FileVariableContribution implements AIVariableContribution, AIVaria #### File Chat Variable Contributions -To enhance usability, additional contributions are implemented to handle argument picking, auto-completion, and drag-and-drop support for file context variables. +To enhance usability, an additional `FrontendVariableContribution` can be provided to handle argument picking, auto-completion, and drag-and-drop support for file context variables. ```ts export class FileChatVariableContribution implements FrontendVariableContribution { @@ -391,7 +402,7 @@ export class FileChatVariableContribution implements FrontendVariableContributio Your custom agent can now use the context variables in various ways. The context variables are available in the `context` property of the `ChatRequestModel` and apply your custom logic to decide in which way your agent passes the context data to the LLM. -Your agents can use the variables `#contextSummary` or `#contextDetails`, which resolve to either a list or the full context, in your system message to transfer the attached context to the LLM. Alternatively, you can use the tool functions `~{context_ListChatContext}` and `~{context_ResolveChatContext}` to allow the LLM obtaining the context on demand. +Your agents can use the predefined variables `#contextSummary` or `#contextDetails` in their prompt, which resolve to either a list or the full context, in your system message to transfer the attached context to the LLM. Alternatively, you can use the tool functions `~{context_ListChatContext}` and `~{context_ResolveChatContext}` to allow the LLM obtaining the context on demand. Please note that ignoring the context completly in you agent while displaying the context user interface in the chat will likely lead to unexpected user results. ### Tool Functions diff --git a/src/docs/user_ai.md b/src/docs/user_ai.md index a753bcc..9fba50f 100644 --- a/src/docs/user_ai.md +++ b/src/docs/user_ai.md @@ -281,11 +281,13 @@ The Theia IDE provides a global chat interface where users can interact with all Some agents produce special results, such as buttons (shown in the screenshot above) or code that can be directly inserted. You can augment your requests in the chat with context by using variables. For example, to refer to the currently selected text, use `#selectedText` in your request. Pressing '#' in ^the chat will show a list of available variables. -You can also pass context files into the chat to further specify the scope of your request. To do this, drag and drop a file into the chat view, or use the auto-completion feature by typing `#file` or directly typing `#`. -Note that the use of the variable `#file:src/my-code.ts` in the chat input text will resolve to the workspace-relative path, while attaching the file into the context, makes the contents available to the chat agent. This allows adding the file content and then referring to it in the chat input text conveniently. +You can also pass context files into the chat to further specify the scope of your request. To do this, drag and drop a file into the chat view, or use the auto-completion feature by typing `#file` or directly typing `#`. +Note that `#file:src/my-code.ts` in the user message is replaced to the workspace-relative path, alongside attaching the file to the context. This allows adding the file content to the context and then referring to the file in the chat input text efficiently in one go. Attach Files to the Context +**Hint:** The context file support in Theia IDE shown above is built on the generic context variable capabilities of the underlying Theia AI framework. It therefore can be customized and extended with tool-specific context variable types. See the [Theia AI documentation](/docs/theia_ai) for more details. + ## AI Configuration The AI Configuration View allows you to review and adapt agent-specific settings. Select an agent on the left side and review its properties on the right: From bb44159e74f3171d7e8ebad095869177a3de4acb Mon Sep 17 00:00:00 2001 From: Philip Langer Date: Fri, 28 Feb 2025 21:45:29 +0100 Subject: [PATCH 3/3] Update src/docs/user_ai.md Co-authored-by: Jonas Helming --- src/docs/user_ai.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/user_ai.md b/src/docs/user_ai.md index 9fba50f..33495af 100644 --- a/src/docs/user_ai.md +++ b/src/docs/user_ai.md @@ -279,7 +279,7 @@ The Theia IDE provides a global chat interface where users can interact with all General AI Chat in the Theia IDE -Some agents produce special results, such as buttons (shown in the screenshot above) or code that can be directly inserted. You can augment your requests in the chat with context by using variables. For example, to refer to the currently selected text, use `#selectedText` in your request. Pressing '#' in ^the chat will show a list of available variables. +Some agents produce special results, such as buttons (shown in the screenshot above) or code that can be directly inserted. You can augment your requests in the chat with context by using variables. For example, to refer to the currently selected text, use `#selectedText` in your request. Pressing '#' in the chat will show a list of available variables. You can also pass context files into the chat to further specify the scope of your request. To do this, drag and drop a file into the chat view, or use the auto-completion feature by typing `#file` or directly typing `#`. Note that `#file:src/my-code.ts` in the user message is replaced to the workspace-relative path, alongside attaching the file to the context. This allows adding the file content to the context and then referring to the file in the chat input text efficiently in one go.