@theia/ai-terminal 1.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ <div align='center'>
2
+
3
+ <br />
4
+
5
+ <img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />
6
+
7
+ <h2>ECLIPSE THEIA - AI Terminal EXTENSION</h2>
8
+
9
+ <hr />
10
+
11
+ </div>
12
+
13
+ ## Description
14
+
15
+ The `@theia/ai-terminal` extension contributes an overlay to the terminal view.\
16
+ The overlay can be used to ask a dedicated `TerminalAgent` for suggestions of terminal commands.
17
+
18
+ ## Additional Information
19
+
20
+ - [Theia - GitHub](https://github.com/eclipse-theia/theia)
21
+ - [Theia - Website](https://theia-ide.org/)
22
+
23
+ ## License
24
+
25
+ - [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
26
+ - [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)
27
+
28
+ ## Trademark
29
+
30
+ "Theia" is a trademark of the Eclipse Foundation
31
+ https://www.eclipse.org/theia
@@ -0,0 +1,26 @@
1
+ import { Agent, LanguageModelRegistry, LanguageModelRequirement, PromptService } from '@theia/ai-core/lib/common';
2
+ import { ILogger } from '@theia/core';
3
+ export declare class AiTerminalAgent implements Agent {
4
+ id: string;
5
+ name: string;
6
+ description: string;
7
+ variables: never[];
8
+ functions: never[];
9
+ agentSpecificVariables: {
10
+ name: string;
11
+ usedInPrompt: boolean;
12
+ description: string;
13
+ }[];
14
+ promptTemplates: {
15
+ id: string;
16
+ name: string;
17
+ description: string;
18
+ template: string;
19
+ }[];
20
+ languageModelRequirements: LanguageModelRequirement[];
21
+ protected languageModelRegistry: LanguageModelRegistry;
22
+ protected promptService: PromptService;
23
+ protected logger: ILogger;
24
+ getCommands(userRequest: string, cwd: string, shell: string, recentTerminalContents: string[]): Promise<string[]>;
25
+ }
26
+ //# sourceMappingURL=ai-terminal-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-terminal-agent.d.ts","sourceRoot":"","sources":["../../src/browser/ai-terminal-agent.ts"],"names":[],"mappings":"AAgBA,OAAO,EACH,KAAK,EAGL,qBAAqB,EAAE,wBAAwB,EAC/C,aAAa,EAChB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAUtC,qBACa,eAAgB,YAAW,KAAK;IAEzC,EAAE,SAAwB;IAC1B,IAAI,SAAwB;IAC5B,WAAW,SAEoI;IAC/I,SAAS,UAAM;IACf,SAAS,UAAM;IACf,sBAAsB;;;;QAKpB;IACF,eAAe;;;;;QA4Db;IACF,yBAAyB,EAAE,wBAAwB,EAAE,CAKnD;IAGF,SAAS,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;IAGvD,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC;IAGvC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC;IAEpB,WAAW,CACb,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,sBAAsB,EAAE,MAAM,EAAE,GACjC,OAAO,CAAC,MAAM,EAAE,CAAC;CAuEvB"}
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2024 EclipseSource GmbH.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.AiTerminalAgent = void 0;
19
+ const tslib_1 = require("tslib");
20
+ const common_1 = require("@theia/ai-core/lib/common");
21
+ const core_1 = require("@theia/core");
22
+ const inversify_1 = require("@theia/core/shared/inversify");
23
+ const zod_1 = require("zod");
24
+ const zod_to_json_schema_1 = require("zod-to-json-schema");
25
+ const Commands = zod_1.z.object({
26
+ commands: zod_1.z.array(zod_1.z.string()),
27
+ });
28
+ let AiTerminalAgent = class AiTerminalAgent {
29
+ constructor() {
30
+ this.id = 'Terminal Assistant';
31
+ this.name = 'Terminal Assistant';
32
+ this.description = 'This agent provides assistance to write and execute arbitrary terminal commands. \
33
+ Based on the user\'s request, it suggests commands and allows the user to directly paste and execute them in the terminal. \
34
+ It accesses the current directory, environment and the recent terminal output of the terminal session to provide context-aware assistance';
35
+ this.variables = [];
36
+ this.functions = [];
37
+ this.agentSpecificVariables = [
38
+ { name: 'userRequest', usedInPrompt: true, description: 'The user\'s question or request.' },
39
+ { name: 'shell', usedInPrompt: true, description: 'The shell being used, e.g., /usr/bin/zsh.' },
40
+ { name: 'cwd', usedInPrompt: true, description: 'The current working directory.' },
41
+ { name: 'recentTerminalContents', usedInPrompt: true, description: 'The last 0 to 50 recent lines visible in the terminal.' }
42
+ ];
43
+ this.promptTemplates = [
44
+ {
45
+ id: 'terminal-system',
46
+ name: 'AI Terminal System Prompt',
47
+ description: 'Prompt for the AI Terminal Assistant',
48
+ template: `
49
+ # Instructions
50
+ Generate one or more command suggestions based on the user's request, considering the shell being used,
51
+ the current working directory, and the recent terminal contents. Provide the best suggestion first,
52
+ followed by other relevant suggestions if the user asks for further options.
53
+
54
+ Parameters:
55
+ - user-request: The user's question or request.
56
+ - shell: The shell being used, e.g., /usr/bin/zsh.
57
+ - cwd: The current working directory.
58
+ - recent-terminal-contents: The last 0 to 50 recent lines visible in the terminal.
59
+
60
+ Return the result in the following JSON format:
61
+ {
62
+ "commands": [
63
+ "best_command_suggestion",
64
+ "next_best_command_suggestion",
65
+ "another_command_suggestion"
66
+ ]
67
+ }
68
+
69
+ ## Example
70
+ user-request: "How do I commit changes?"
71
+ shell: "/usr/bin/zsh"
72
+ cwd: "/home/user/project"
73
+ recent-terminal-contents:
74
+ git status
75
+ On branch main
76
+ Your branch is up to date with 'origin/main'.
77
+ nothing to commit, working tree clean
78
+
79
+ ## Expected JSON output
80
+ \`\`\`json
81
+ \{
82
+ "commands": [
83
+ "git commit",
84
+ "git commit --amend",
85
+ "git commit -a"
86
+ ]
87
+ }
88
+ \`\`\`
89
+ `
90
+ },
91
+ {
92
+ id: 'terminal-user',
93
+ name: 'AI Terminal User Prompt',
94
+ description: 'Prompt that contains the user request',
95
+ template: `
96
+ user-request: {{userRequest}}
97
+ shell: {{shell}}
98
+ cwd: {{cwd}}
99
+ recent-terminal-contents:
100
+ {{recentTerminalContents}}
101
+ `
102
+ }
103
+ ];
104
+ this.languageModelRequirements = [
105
+ {
106
+ purpose: 'suggest-terminal-commands',
107
+ identifier: 'openai/gpt-4o',
108
+ }
109
+ ];
110
+ }
111
+ async getCommands(userRequest, cwd, shell, recentTerminalContents) {
112
+ const lm = await this.languageModelRegistry.selectLanguageModel({
113
+ agent: this.id,
114
+ ...this.languageModelRequirements[0]
115
+ });
116
+ if (!lm) {
117
+ this.logger.error('No language model available for the AI Terminal Agent.');
118
+ return [];
119
+ }
120
+ const parameters = {
121
+ userRequest,
122
+ shell,
123
+ cwd,
124
+ recentTerminalContents
125
+ };
126
+ const systemPrompt = await this.promptService.getPrompt('terminal-system', parameters).then(p => p === null || p === void 0 ? void 0 : p.text);
127
+ const userPrompt = await this.promptService.getPrompt('terminal-user', parameters).then(p => p === null || p === void 0 ? void 0 : p.text);
128
+ if (!systemPrompt || !userPrompt) {
129
+ this.logger.error('The prompt service didn\'t return prompts for the AI Terminal Agent.');
130
+ return [];
131
+ }
132
+ try {
133
+ const result = await lm.request({
134
+ messages: [
135
+ {
136
+ actor: 'ai',
137
+ type: 'text',
138
+ query: systemPrompt
139
+ },
140
+ {
141
+ actor: 'user',
142
+ type: 'text',
143
+ query: userPrompt
144
+ }
145
+ ],
146
+ response_format: {
147
+ type: 'json_schema',
148
+ json_schema: {
149
+ name: 'terminal-commands',
150
+ description: 'Suggested terminal commands based on the user request',
151
+ schema: (0, zod_to_json_schema_1.default)(Commands)
152
+ }
153
+ }
154
+ });
155
+ if ((0, common_1.isLanguageModelParsedResponse)(result)) {
156
+ // model returned structured output
157
+ const parsedResult = Commands.safeParse(result.parsed);
158
+ if (parsedResult.success) {
159
+ return parsedResult.data.commands;
160
+ }
161
+ }
162
+ // fall back to agent-based parsing of result
163
+ const jsonResult = await (0, common_1.getJsonOfResponse)(result);
164
+ const parsedJsonResult = Commands.safeParse(jsonResult);
165
+ if (parsedJsonResult.success) {
166
+ return parsedJsonResult.data.commands;
167
+ }
168
+ return [];
169
+ }
170
+ catch (error) {
171
+ this.logger.error('Error obtaining the command suggestions.', error);
172
+ return [];
173
+ }
174
+ }
175
+ };
176
+ exports.AiTerminalAgent = AiTerminalAgent;
177
+ tslib_1.__decorate([
178
+ (0, inversify_1.inject)(common_1.LanguageModelRegistry),
179
+ tslib_1.__metadata("design:type", Object)
180
+ ], AiTerminalAgent.prototype, "languageModelRegistry", void 0);
181
+ tslib_1.__decorate([
182
+ (0, inversify_1.inject)(common_1.PromptService),
183
+ tslib_1.__metadata("design:type", Object)
184
+ ], AiTerminalAgent.prototype, "promptService", void 0);
185
+ tslib_1.__decorate([
186
+ (0, inversify_1.inject)(core_1.ILogger),
187
+ tslib_1.__metadata("design:type", Object)
188
+ ], AiTerminalAgent.prototype, "logger", void 0);
189
+ exports.AiTerminalAgent = AiTerminalAgent = tslib_1.__decorate([
190
+ (0, inversify_1.injectable)()
191
+ ], AiTerminalAgent);
192
+ //# sourceMappingURL=ai-terminal-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-terminal-agent.js","sourceRoot":"","sources":["../../src/browser/ai-terminal-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { CommandContribution, CommandRegistry, MenuContribution, MenuModelRegistry } from '@theia/core';
2
+ import { KeybindingContribution, KeybindingRegistry } from '@theia/core/lib/browser';
3
+ import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service';
4
+ import { AiTerminalAgent } from './ai-terminal-agent';
5
+ import { AICommandHandlerFactory } from '@theia/ai-core/lib/browser/ai-command-handler-factory';
6
+ export declare class AiTerminalCommandContribution implements CommandContribution, MenuContribution, KeybindingContribution {
7
+ protected terminalService: TerminalService;
8
+ protected terminalAgent: AiTerminalAgent;
9
+ protected commandHandlerFactory: AICommandHandlerFactory;
10
+ private readonly agentService;
11
+ registerKeybindings(keybindings: KeybindingRegistry): void;
12
+ registerMenus(menus: MenuModelRegistry): void;
13
+ registerCommands(commands: CommandRegistry): void;
14
+ }
15
+ //# sourceMappingURL=ai-terminal-contribution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-terminal-contribution.d.ts","sourceRoot":"","sources":["../../src/browser/ai-terminal-contribution.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACxG,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAErF,OAAO,EAAE,eAAe,EAAE,MAAM,mDAAmD,CAAC;AAGpF,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uDAAuD,CAAC;AAQhG,qBACa,6BAA8B,YAAW,mBAAmB,EAAE,gBAAgB,EAAE,sBAAsB;IAG/G,SAAS,CAAC,eAAe,EAAE,eAAe,CAAC;IAG3C,SAAS,CAAC,aAAa,EAAE,eAAe,CAAC;IAGzC,SAAS,CAAC,qBAAqB,EAAE,uBAAuB,CAAC;IAGzD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAE5C,mBAAmB,CAAC,WAAW,EAAE,kBAAkB,GAAG,IAAI;IAO1D,aAAa,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAM7C,gBAAgB,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;CAYpD"}
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2024 EclipseSource GmbH.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.AiTerminalCommandContribution = void 0;
19
+ const tslib_1 = require("tslib");
20
+ const browser_1 = require("@theia/ai-core/lib/browser");
21
+ const inversify_1 = require("@theia/core/shared/inversify");
22
+ const terminal_service_1 = require("@theia/terminal/lib/browser/base/terminal-service");
23
+ const terminal_frontend_contribution_1 = require("@theia/terminal/lib/browser/terminal-frontend-contribution");
24
+ const terminal_widget_impl_1 = require("@theia/terminal/lib/browser/terminal-widget-impl");
25
+ const ai_terminal_agent_1 = require("./ai-terminal-agent");
26
+ const ai_command_handler_factory_1 = require("@theia/ai-core/lib/browser/ai-command-handler-factory");
27
+ const ai_core_1 = require("@theia/ai-core");
28
+ const AI_TERMINAL_COMMAND = {
29
+ id: 'ai-terminal:open',
30
+ label: 'Ask the AI'
31
+ };
32
+ let AiTerminalCommandContribution = class AiTerminalCommandContribution {
33
+ registerKeybindings(keybindings) {
34
+ keybindings.registerKeybinding({
35
+ command: AI_TERMINAL_COMMAND.id,
36
+ keybinding: 'ctrlcmd+i',
37
+ when: `terminalFocus && ${browser_1.EXPERIMENTAL_AI_CONTEXT_KEY}`
38
+ });
39
+ }
40
+ registerMenus(menus) {
41
+ menus.registerMenuAction([...terminal_frontend_contribution_1.TerminalMenus.TERMINAL_CONTEXT_MENU, '_5'], {
42
+ when: browser_1.EXPERIMENTAL_AI_CONTEXT_KEY,
43
+ commandId: AI_TERMINAL_COMMAND.id
44
+ });
45
+ }
46
+ registerCommands(commands) {
47
+ commands.registerCommand(AI_TERMINAL_COMMAND, this.commandHandlerFactory({
48
+ execute: () => {
49
+ if (this.terminalService.currentTerminal instanceof terminal_widget_impl_1.TerminalWidgetImpl && this.agentService.isEnabled(this.terminalAgent.id)) {
50
+ new AiTerminalChatWidget(this.terminalService.currentTerminal, this.terminalAgent);
51
+ }
52
+ }
53
+ }));
54
+ }
55
+ };
56
+ exports.AiTerminalCommandContribution = AiTerminalCommandContribution;
57
+ tslib_1.__decorate([
58
+ (0, inversify_1.inject)(terminal_service_1.TerminalService),
59
+ tslib_1.__metadata("design:type", Object)
60
+ ], AiTerminalCommandContribution.prototype, "terminalService", void 0);
61
+ tslib_1.__decorate([
62
+ (0, inversify_1.inject)(ai_terminal_agent_1.AiTerminalAgent),
63
+ tslib_1.__metadata("design:type", ai_terminal_agent_1.AiTerminalAgent)
64
+ ], AiTerminalCommandContribution.prototype, "terminalAgent", void 0);
65
+ tslib_1.__decorate([
66
+ (0, inversify_1.inject)(ai_command_handler_factory_1.AICommandHandlerFactory),
67
+ tslib_1.__metadata("design:type", Function)
68
+ ], AiTerminalCommandContribution.prototype, "commandHandlerFactory", void 0);
69
+ tslib_1.__decorate([
70
+ (0, inversify_1.inject)(ai_core_1.AgentService),
71
+ tslib_1.__metadata("design:type", Object)
72
+ ], AiTerminalCommandContribution.prototype, "agentService", void 0);
73
+ exports.AiTerminalCommandContribution = AiTerminalCommandContribution = tslib_1.__decorate([
74
+ (0, inversify_1.injectable)()
75
+ ], AiTerminalCommandContribution);
76
+ class AiTerminalChatWidget {
77
+ constructor(terminalWidget, terminalAgent) {
78
+ this.terminalWidget = terminalWidget;
79
+ this.terminalAgent = terminalAgent;
80
+ this.haveResult = false;
81
+ this.chatContainer = document.createElement('div');
82
+ this.chatContainer.className = 'ai-terminal-chat-container';
83
+ const chatCloseButton = document.createElement('span');
84
+ chatCloseButton.className = 'closeButton codicon codicon-close';
85
+ chatCloseButton.onclick = () => this.dispose();
86
+ this.chatContainer.appendChild(chatCloseButton);
87
+ const chatResultContainer = document.createElement('div');
88
+ chatResultContainer.className = 'ai-terminal-chat-result';
89
+ this.chatResultParagraph = document.createElement('p');
90
+ this.chatResultParagraph.textContent = 'How can I help you?';
91
+ chatResultContainer.appendChild(this.chatResultParagraph);
92
+ this.chatContainer.appendChild(chatResultContainer);
93
+ this.chatInputContainer = document.createElement('div');
94
+ this.chatInputContainer.className = 'ai-terminal-chat-input-container';
95
+ this.chatInput = document.createElement('textarea');
96
+ this.chatInput.className = 'theia-input theia-ChatInput';
97
+ this.chatInput.placeholder = 'Ask about a terminal command...';
98
+ this.chatInput.onkeydown = event => {
99
+ if (event.key === 'Enter' && !event.shiftKey) {
100
+ event.preventDefault();
101
+ if (!this.haveResult) {
102
+ this.send();
103
+ }
104
+ else {
105
+ this.terminalWidget.sendText(this.chatResultParagraph.innerText);
106
+ this.dispose();
107
+ }
108
+ }
109
+ else if (event.key === 'Escape') {
110
+ this.dispose();
111
+ }
112
+ else if (event.key === 'ArrowUp' && this.haveResult) {
113
+ this.updateChatResult(this.getNextCommandIndex(1));
114
+ }
115
+ else if (event.key === 'ArrowDown' && this.haveResult) {
116
+ this.updateChatResult(this.getNextCommandIndex(-1));
117
+ }
118
+ };
119
+ this.chatInputContainer.appendChild(this.chatInput);
120
+ const chatInputOptionsContainer = document.createElement('div');
121
+ const chatInputOptionsSpan = document.createElement('span');
122
+ chatInputOptionsSpan.className = 'codicon codicon-send option';
123
+ chatInputOptionsSpan.title = 'Send';
124
+ chatInputOptionsSpan.onclick = () => this.send();
125
+ chatInputOptionsContainer.appendChild(chatInputOptionsSpan);
126
+ this.chatInputContainer.appendChild(chatInputOptionsContainer);
127
+ this.chatContainer.appendChild(this.chatInputContainer);
128
+ terminalWidget.node.appendChild(this.chatContainer);
129
+ this.chatInput.focus();
130
+ }
131
+ async send() {
132
+ const userRequest = this.chatInput.value;
133
+ if (userRequest) {
134
+ this.chatInput.value = '';
135
+ this.chatResultParagraph.innerText = 'Loading';
136
+ this.chatResultParagraph.className = 'loading';
137
+ const cwd = (await this.terminalWidget.cwd).toString();
138
+ const processInfo = await this.terminalWidget.processInfo;
139
+ const shell = processInfo.executable;
140
+ const recentTerminalContents = this.getRecentTerminalCommands();
141
+ this.commands = await this.terminalAgent.getCommands(userRequest, cwd, shell, recentTerminalContents);
142
+ if (this.commands.length > 0) {
143
+ this.chatResultParagraph.className = 'command';
144
+ this.chatResultParagraph.innerText = this.commands[0];
145
+ this.chatInput.placeholder = 'Hit enter to confirm';
146
+ if (this.commands.length > 1) {
147
+ this.chatInput.placeholder += ' or use ⇅ to show alternatives...';
148
+ }
149
+ this.haveResult = true;
150
+ }
151
+ else {
152
+ this.chatResultParagraph.className = '';
153
+ this.chatResultParagraph.innerText = 'No results';
154
+ this.chatInput.placeholder = 'Try again...';
155
+ }
156
+ }
157
+ }
158
+ getRecentTerminalCommands() {
159
+ const maxLines = 100;
160
+ return this.terminalWidget.buffer.getLines(0, this.terminalWidget.buffer.length > maxLines ? maxLines : this.terminalWidget.buffer.length);
161
+ }
162
+ getNextCommandIndex(step) {
163
+ const currentIndex = this.commands.indexOf(this.chatResultParagraph.innerText);
164
+ const nextIndex = (currentIndex + step + this.commands.length) % this.commands.length;
165
+ return nextIndex;
166
+ }
167
+ updateChatResult(index) {
168
+ this.chatResultParagraph.innerText = this.commands[index];
169
+ }
170
+ dispose() {
171
+ this.chatInput.value = '';
172
+ this.terminalWidget.node.removeChild(this.chatContainer);
173
+ this.terminalWidget.getTerminal().focus();
174
+ }
175
+ }
176
+ //# sourceMappingURL=ai-terminal-contribution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-terminal-contribution.js","sourceRoot":"","sources":["../../src/browser/ai-terminal-contribution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { ContainerModule } from '@theia/core/shared/inversify';
2
+ import '../../src/browser/style/ai-terminal.css';
3
+ declare const _default: ContainerModule;
4
+ export default _default;
5
+ //# sourceMappingURL=ai-terminal-frontend-module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-terminal-frontend-module.d.ts","sourceRoot":"","sources":["../../src/browser/ai-terminal-frontend-module.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAI/D,OAAO,yCAAyC,CAAC;;AAEjD,wBAQG"}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2024 EclipseSource GmbH.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ const common_1 = require("@theia/ai-core/lib/common");
19
+ const core_1 = require("@theia/core");
20
+ const browser_1 = require("@theia/core/lib/browser");
21
+ const inversify_1 = require("@theia/core/shared/inversify");
22
+ const ai_terminal_agent_1 = require("./ai-terminal-agent");
23
+ const ai_terminal_contribution_1 = require("./ai-terminal-contribution");
24
+ require("../../src/browser/style/ai-terminal.css");
25
+ exports.default = new inversify_1.ContainerModule(bind => {
26
+ bind(ai_terminal_contribution_1.AiTerminalCommandContribution).toSelf().inSingletonScope();
27
+ for (const identifier of [core_1.CommandContribution, core_1.MenuContribution, browser_1.KeybindingContribution]) {
28
+ bind(identifier).toService(ai_terminal_contribution_1.AiTerminalCommandContribution);
29
+ }
30
+ bind(ai_terminal_agent_1.AiTerminalAgent).toSelf().inSingletonScope();
31
+ bind(common_1.Agent).toService(ai_terminal_agent_1.AiTerminalAgent);
32
+ });
33
+ //# sourceMappingURL=ai-terminal-frontend-module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-terminal-frontend-module.js","sourceRoot":"","sources":["../../src/browser/ai-terminal-frontend-module.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;AAEhF,sDAAkD;AAClD,sCAAoE;AACpE,qDAAiE;AACjE,4DAA+D;AAC/D,2DAAsD;AACtD,yEAA2E;AAE3E,mDAAiD;AAEjD,kBAAe,IAAI,2BAAe,CAAC,IAAI,CAAC,EAAE;IACtC,IAAI,CAAC,wDAA6B,CAAC,CAAC,MAAM,EAAE,CAAC,gBAAgB,EAAE,CAAC;IAChE,KAAK,MAAM,UAAU,IAAI,CAAC,0BAAmB,EAAE,uBAAgB,EAAE,gCAAsB,CAAC,EAAE,CAAC;QACvF,IAAI,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,wDAA6B,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,CAAC,mCAAe,CAAC,CAAC,MAAM,EAAE,CAAC,gBAAgB,EAAE,CAAC;IAClD,IAAI,CAAC,cAAK,CAAC,CAAC,SAAS,CAAC,mCAAe,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=package.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package.spec.d.ts","sourceRoot":"","sources":["../src/package.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 EclipseSource GmbH and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+ /* note: this bogus test file is required so that
17
+ we are able to run mocha unit tests on this
18
+ package, without having any actual unit tests in it.
19
+ This way a coverage report will be generated,
20
+ showing 0% coverage, instead of no report.
21
+ This file can be removed once we have real unit
22
+ tests in place. */
23
+ describe('ai-terminal package', () => {
24
+ it('support code coverage statistics', () => true);
25
+ });
26
+ //# sourceMappingURL=package.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package.spec.js","sourceRoot":"","sources":["../src/package.spec.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,oDAAoD;AACpD,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAEhF;;;;;;qBAMqB;AAErB,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IAEjC,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@theia/ai-terminal",
3
+ "version": "1.54.0",
4
+ "description": "Theia - AI Terminal Extension",
5
+ "dependencies": {
6
+ "@theia/ai-chat": "1.54.0",
7
+ "@theia/ai-core": "1.54.0",
8
+ "@theia/core": "1.54.0",
9
+ "@theia/terminal": "1.54.0",
10
+ "zod": "^3.23.8",
11
+ "zod-to-json-schema": "^3.23.2"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "theiaExtensions": [
17
+ {
18
+ "frontend": "lib/browser/ai-terminal-frontend-module"
19
+ }
20
+ ],
21
+ "keywords": [
22
+ "theia-extension"
23
+ ],
24
+ "license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/eclipse-theia/theia.git"
28
+ },
29
+ "bugs": {
30
+ "url": "https://github.com/eclipse-theia/theia/issues"
31
+ },
32
+ "homepage": "https://github.com/eclipse-theia/theia",
33
+ "files": [
34
+ "lib",
35
+ "src"
36
+ ],
37
+ "scripts": {
38
+ "build": "theiaext build",
39
+ "clean": "theiaext clean",
40
+ "compile": "theiaext compile",
41
+ "lint": "theiaext lint",
42
+ "test": "theiaext test",
43
+ "watch": "theiaext watch"
44
+ },
45
+ "devDependencies": {
46
+ "@theia/ext-scripts": "1.54.0"
47
+ },
48
+ "nyc": {
49
+ "extends": "../../configs/nyc.json"
50
+ },
51
+ "gitHead": "8fb36a237db744cff6e78eaff1481e1f36bb7a69"
52
+ }
@@ -0,0 +1,203 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 EclipseSource GmbH.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import {
18
+ Agent,
19
+ getJsonOfResponse,
20
+ isLanguageModelParsedResponse,
21
+ LanguageModelRegistry, LanguageModelRequirement,
22
+ PromptService
23
+ } from '@theia/ai-core/lib/common';
24
+ import { ILogger } from '@theia/core';
25
+ import { inject, injectable } from '@theia/core/shared/inversify';
26
+ import { z } from 'zod';
27
+ import zodToJsonSchema from 'zod-to-json-schema';
28
+
29
+ const Commands = z.object({
30
+ commands: z.array(z.string()),
31
+ });
32
+ type Commands = z.infer<typeof Commands>;
33
+
34
+ @injectable()
35
+ export class AiTerminalAgent implements Agent {
36
+
37
+ id = 'Terminal Assistant';
38
+ name = 'Terminal Assistant';
39
+ description = 'This agent provides assistance to write and execute arbitrary terminal commands. \
40
+ Based on the user\'s request, it suggests commands and allows the user to directly paste and execute them in the terminal. \
41
+ It accesses the current directory, environment and the recent terminal output of the terminal session to provide context-aware assistance';
42
+ variables = [];
43
+ functions = [];
44
+ agentSpecificVariables = [
45
+ { name: 'userRequest', usedInPrompt: true, description: 'The user\'s question or request.' },
46
+ { name: 'shell', usedInPrompt: true, description: 'The shell being used, e.g., /usr/bin/zsh.' },
47
+ { name: 'cwd', usedInPrompt: true, description: 'The current working directory.' },
48
+ { name: 'recentTerminalContents', usedInPrompt: true, description: 'The last 0 to 50 recent lines visible in the terminal.' }
49
+ ];
50
+ promptTemplates = [
51
+ {
52
+ id: 'terminal-system',
53
+ name: 'AI Terminal System Prompt',
54
+ description: 'Prompt for the AI Terminal Assistant',
55
+ template: `
56
+ # Instructions
57
+ Generate one or more command suggestions based on the user's request, considering the shell being used,
58
+ the current working directory, and the recent terminal contents. Provide the best suggestion first,
59
+ followed by other relevant suggestions if the user asks for further options.
60
+
61
+ Parameters:
62
+ - user-request: The user's question or request.
63
+ - shell: The shell being used, e.g., /usr/bin/zsh.
64
+ - cwd: The current working directory.
65
+ - recent-terminal-contents: The last 0 to 50 recent lines visible in the terminal.
66
+
67
+ Return the result in the following JSON format:
68
+ {
69
+ "commands": [
70
+ "best_command_suggestion",
71
+ "next_best_command_suggestion",
72
+ "another_command_suggestion"
73
+ ]
74
+ }
75
+
76
+ ## Example
77
+ user-request: "How do I commit changes?"
78
+ shell: "/usr/bin/zsh"
79
+ cwd: "/home/user/project"
80
+ recent-terminal-contents:
81
+ git status
82
+ On branch main
83
+ Your branch is up to date with 'origin/main'.
84
+ nothing to commit, working tree clean
85
+
86
+ ## Expected JSON output
87
+ \`\`\`json
88
+ \{
89
+ "commands": [
90
+ "git commit",
91
+ "git commit --amend",
92
+ "git commit -a"
93
+ ]
94
+ }
95
+ \`\`\`
96
+ `
97
+ },
98
+ {
99
+ id: 'terminal-user',
100
+ name: 'AI Terminal User Prompt',
101
+ description: 'Prompt that contains the user request',
102
+ template: `
103
+ user-request: {{userRequest}}
104
+ shell: {{shell}}
105
+ cwd: {{cwd}}
106
+ recent-terminal-contents:
107
+ {{recentTerminalContents}}
108
+ `
109
+ }
110
+ ];
111
+ languageModelRequirements: LanguageModelRequirement[] = [
112
+ {
113
+ purpose: 'suggest-terminal-commands',
114
+ identifier: 'openai/gpt-4o',
115
+ }
116
+ ];
117
+
118
+ @inject(LanguageModelRegistry)
119
+ protected languageModelRegistry: LanguageModelRegistry;
120
+
121
+ @inject(PromptService)
122
+ protected promptService: PromptService;
123
+
124
+ @inject(ILogger)
125
+ protected logger: ILogger;
126
+
127
+ async getCommands(
128
+ userRequest: string,
129
+ cwd: string,
130
+ shell: string,
131
+ recentTerminalContents: string[],
132
+ ): Promise<string[]> {
133
+ const lm = await this.languageModelRegistry.selectLanguageModel({
134
+ agent: this.id,
135
+ ...this.languageModelRequirements[0]
136
+ });
137
+ if (!lm) {
138
+ this.logger.error('No language model available for the AI Terminal Agent.');
139
+ return [];
140
+ }
141
+
142
+ const parameters = {
143
+ userRequest,
144
+ shell,
145
+ cwd,
146
+ recentTerminalContents
147
+ };
148
+
149
+ const systemPrompt = await this.promptService.getPrompt('terminal-system', parameters).then(p => p?.text);
150
+ const userPrompt = await this.promptService.getPrompt('terminal-user', parameters).then(p => p?.text);
151
+ if (!systemPrompt || !userPrompt) {
152
+ this.logger.error('The prompt service didn\'t return prompts for the AI Terminal Agent.');
153
+ return [];
154
+ }
155
+
156
+ try {
157
+ const result = await lm.request({
158
+ messages: [
159
+ {
160
+ actor: 'ai',
161
+ type: 'text',
162
+ query: systemPrompt
163
+ },
164
+ {
165
+ actor: 'user',
166
+ type: 'text',
167
+ query: userPrompt
168
+ }
169
+ ],
170
+ response_format: {
171
+ type: 'json_schema',
172
+ json_schema: {
173
+ name: 'terminal-commands',
174
+ description: 'Suggested terminal commands based on the user request',
175
+ schema: zodToJsonSchema(Commands)
176
+ }
177
+ }
178
+ });
179
+
180
+ if (isLanguageModelParsedResponse(result)) {
181
+ // model returned structured output
182
+ const parsedResult = Commands.safeParse(result.parsed);
183
+ if (parsedResult.success) {
184
+ return parsedResult.data.commands;
185
+ }
186
+ }
187
+
188
+ // fall back to agent-based parsing of result
189
+ const jsonResult = await getJsonOfResponse(result);
190
+ const parsedJsonResult = Commands.safeParse(jsonResult);
191
+ if (parsedJsonResult.success) {
192
+ return parsedJsonResult.data.commands;
193
+ }
194
+
195
+ return [];
196
+
197
+ } catch (error) {
198
+ this.logger.error('Error obtaining the command suggestions.', error);
199
+ return [];
200
+ }
201
+ }
202
+
203
+ }
@@ -0,0 +1,197 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 EclipseSource GmbH.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { EXPERIMENTAL_AI_CONTEXT_KEY } from '@theia/ai-core/lib/browser';
18
+ import { CommandContribution, CommandRegistry, MenuContribution, MenuModelRegistry } from '@theia/core';
19
+ import { KeybindingContribution, KeybindingRegistry } from '@theia/core/lib/browser';
20
+ import { inject, injectable } from '@theia/core/shared/inversify';
21
+ import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service';
22
+ import { TerminalMenus } from '@theia/terminal/lib/browser/terminal-frontend-contribution';
23
+ import { TerminalWidgetImpl } from '@theia/terminal/lib/browser/terminal-widget-impl';
24
+ import { AiTerminalAgent } from './ai-terminal-agent';
25
+ import { AICommandHandlerFactory } from '@theia/ai-core/lib/browser/ai-command-handler-factory';
26
+ import { AgentService } from '@theia/ai-core';
27
+
28
+ const AI_TERMINAL_COMMAND = {
29
+ id: 'ai-terminal:open',
30
+ label: 'Ask the AI'
31
+ };
32
+
33
+ @injectable()
34
+ export class AiTerminalCommandContribution implements CommandContribution, MenuContribution, KeybindingContribution {
35
+
36
+ @inject(TerminalService)
37
+ protected terminalService: TerminalService;
38
+
39
+ @inject(AiTerminalAgent)
40
+ protected terminalAgent: AiTerminalAgent;
41
+
42
+ @inject(AICommandHandlerFactory)
43
+ protected commandHandlerFactory: AICommandHandlerFactory;
44
+
45
+ @inject(AgentService)
46
+ private readonly agentService: AgentService;
47
+
48
+ registerKeybindings(keybindings: KeybindingRegistry): void {
49
+ keybindings.registerKeybinding({
50
+ command: AI_TERMINAL_COMMAND.id,
51
+ keybinding: 'ctrlcmd+i',
52
+ when: `terminalFocus && ${EXPERIMENTAL_AI_CONTEXT_KEY}`
53
+ });
54
+ }
55
+ registerMenus(menus: MenuModelRegistry): void {
56
+ menus.registerMenuAction([...TerminalMenus.TERMINAL_CONTEXT_MENU, '_5'], {
57
+ when: EXPERIMENTAL_AI_CONTEXT_KEY,
58
+ commandId: AI_TERMINAL_COMMAND.id
59
+ });
60
+ }
61
+ registerCommands(commands: CommandRegistry): void {
62
+ commands.registerCommand(AI_TERMINAL_COMMAND, this.commandHandlerFactory({
63
+ execute: () => {
64
+ if (this.terminalService.currentTerminal instanceof TerminalWidgetImpl && this.agentService.isEnabled(this.terminalAgent.id)) {
65
+ new AiTerminalChatWidget(
66
+ this.terminalService.currentTerminal,
67
+ this.terminalAgent
68
+ );
69
+ }
70
+ }
71
+ }));
72
+ }
73
+ }
74
+
75
+ class AiTerminalChatWidget {
76
+
77
+ protected chatContainer: HTMLDivElement;
78
+ protected chatInput: HTMLTextAreaElement;
79
+ protected chatResultParagraph: HTMLParagraphElement;
80
+ protected chatInputContainer: HTMLDivElement;
81
+
82
+ protected haveResult = false;
83
+ commands: string[];
84
+
85
+ constructor(
86
+ protected terminalWidget: TerminalWidgetImpl,
87
+ protected terminalAgent: AiTerminalAgent
88
+ ) {
89
+ this.chatContainer = document.createElement('div');
90
+ this.chatContainer.className = 'ai-terminal-chat-container';
91
+
92
+ const chatCloseButton = document.createElement('span');
93
+ chatCloseButton.className = 'closeButton codicon codicon-close';
94
+ chatCloseButton.onclick = () => this.dispose();
95
+ this.chatContainer.appendChild(chatCloseButton);
96
+
97
+ const chatResultContainer = document.createElement('div');
98
+ chatResultContainer.className = 'ai-terminal-chat-result';
99
+ this.chatResultParagraph = document.createElement('p');
100
+ this.chatResultParagraph.textContent = 'How can I help you?';
101
+ chatResultContainer.appendChild(this.chatResultParagraph);
102
+ this.chatContainer.appendChild(chatResultContainer);
103
+
104
+ this.chatInputContainer = document.createElement('div');
105
+ this.chatInputContainer.className = 'ai-terminal-chat-input-container';
106
+
107
+ this.chatInput = document.createElement('textarea');
108
+ this.chatInput.className = 'theia-input theia-ChatInput';
109
+ this.chatInput.placeholder = 'Ask about a terminal command...';
110
+ this.chatInput.onkeydown = event => {
111
+ if (event.key === 'Enter' && !event.shiftKey) {
112
+ event.preventDefault();
113
+ if (!this.haveResult) {
114
+ this.send();
115
+ } else {
116
+ this.terminalWidget.sendText(this.chatResultParagraph.innerText);
117
+ this.dispose();
118
+ }
119
+ } else if (event.key === 'Escape') {
120
+ this.dispose();
121
+ } else if (event.key === 'ArrowUp' && this.haveResult) {
122
+ this.updateChatResult(this.getNextCommandIndex(1));
123
+ } else if (event.key === 'ArrowDown' && this.haveResult) {
124
+ this.updateChatResult(this.getNextCommandIndex(-1));
125
+ }
126
+ };
127
+ this.chatInputContainer.appendChild(this.chatInput);
128
+
129
+ const chatInputOptionsContainer = document.createElement('div');
130
+ const chatInputOptionsSpan = document.createElement('span');
131
+ chatInputOptionsSpan.className = 'codicon codicon-send option';
132
+ chatInputOptionsSpan.title = 'Send';
133
+ chatInputOptionsSpan.onclick = () => this.send();
134
+ chatInputOptionsContainer.appendChild(chatInputOptionsSpan);
135
+ this.chatInputContainer.appendChild(chatInputOptionsContainer);
136
+
137
+ this.chatContainer.appendChild(this.chatInputContainer);
138
+
139
+ terminalWidget.node.appendChild(this.chatContainer);
140
+
141
+ this.chatInput.focus();
142
+ }
143
+
144
+ protected async send(): Promise<void> {
145
+ const userRequest = this.chatInput.value;
146
+ if (userRequest) {
147
+ this.chatInput.value = '';
148
+
149
+ this.chatResultParagraph.innerText = 'Loading';
150
+ this.chatResultParagraph.className = 'loading';
151
+
152
+ const cwd = (await this.terminalWidget.cwd).toString();
153
+ const processInfo = await this.terminalWidget.processInfo;
154
+ const shell = processInfo.executable;
155
+ const recentTerminalContents = this.getRecentTerminalCommands();
156
+
157
+ this.commands = await this.terminalAgent.getCommands(userRequest, cwd, shell, recentTerminalContents);
158
+
159
+ if (this.commands.length > 0) {
160
+ this.chatResultParagraph.className = 'command';
161
+ this.chatResultParagraph.innerText = this.commands[0];
162
+ this.chatInput.placeholder = 'Hit enter to confirm';
163
+ if (this.commands.length > 1) {
164
+ this.chatInput.placeholder += ' or use ⇅ to show alternatives...';
165
+ }
166
+ this.haveResult = true;
167
+ } else {
168
+ this.chatResultParagraph.className = '';
169
+ this.chatResultParagraph.innerText = 'No results';
170
+ this.chatInput.placeholder = 'Try again...';
171
+ }
172
+ }
173
+ }
174
+
175
+ protected getRecentTerminalCommands(): string[] {
176
+ const maxLines = 100;
177
+ return this.terminalWidget.buffer.getLines(0,
178
+ this.terminalWidget.buffer.length > maxLines ? maxLines : this.terminalWidget.buffer.length
179
+ );
180
+ }
181
+
182
+ protected getNextCommandIndex(step: number): number {
183
+ const currentIndex = this.commands.indexOf(this.chatResultParagraph.innerText);
184
+ const nextIndex = (currentIndex + step + this.commands.length) % this.commands.length;
185
+ return nextIndex;
186
+ }
187
+
188
+ protected updateChatResult(index: number): void {
189
+ this.chatResultParagraph.innerText = this.commands[index];
190
+ }
191
+
192
+ protected dispose(): void {
193
+ this.chatInput.value = '';
194
+ this.terminalWidget.node.removeChild(this.chatContainer);
195
+ this.terminalWidget.getTerminal().focus();
196
+ }
197
+ }
@@ -0,0 +1,34 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 EclipseSource GmbH.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { Agent } from '@theia/ai-core/lib/common';
18
+ import { CommandContribution, MenuContribution } from '@theia/core';
19
+ import { KeybindingContribution } from '@theia/core/lib/browser';
20
+ import { ContainerModule } from '@theia/core/shared/inversify';
21
+ import { AiTerminalAgent } from './ai-terminal-agent';
22
+ import { AiTerminalCommandContribution } from './ai-terminal-contribution';
23
+
24
+ import '../../src/browser/style/ai-terminal.css';
25
+
26
+ export default new ContainerModule(bind => {
27
+ bind(AiTerminalCommandContribution).toSelf().inSingletonScope();
28
+ for (const identifier of [CommandContribution, MenuContribution, KeybindingContribution]) {
29
+ bind(identifier).toService(AiTerminalCommandContribution);
30
+ }
31
+
32
+ bind(AiTerminalAgent).toSelf().inSingletonScope();
33
+ bind(Agent).toService(AiTerminalAgent);
34
+ });
@@ -0,0 +1,94 @@
1
+ .ai-terminal-chat-container {
2
+ position: absolute;
3
+ bottom: 0;
4
+ left: 50%;
5
+ transform: translateX(-50%);
6
+ width: 100%;
7
+ max-width: 500px;
8
+ padding: 10px;
9
+ box-sizing: border-box;
10
+ background: var(--theia-menu-background);
11
+ color: var(--theia-menu-foreground);
12
+ margin-bottom: 12px;
13
+ display: flex;
14
+ flex-direction: column;
15
+ align-items: center;
16
+ border: 1px solid var(--theia-menu-border);
17
+ }
18
+
19
+ .ai-terminal-chat-container .closeButton {
20
+ position: absolute;
21
+ top: 1em;
22
+ right: 1em;
23
+ cursor: pointer;
24
+ }
25
+
26
+ .ai-terminal-chat-container .closeButton:hover {
27
+ color: var(--theia-menu-foreground);
28
+ }
29
+
30
+ .ai-terminal-chat-result {
31
+ width: 100%;
32
+ margin-bottom: 10px;
33
+ }
34
+
35
+ .ai-terminal-chat-input-container {
36
+ width: 100%;
37
+ display: flex;
38
+ align-items: center;
39
+ }
40
+
41
+ .ai-terminal-chat-input-container textarea {
42
+ flex-grow: 1;
43
+ height: 36px;
44
+ background-color: var(--theia-input-background);
45
+ border-radius: 4px;
46
+ box-sizing: border-box;
47
+ padding: 8px;
48
+ resize: none;
49
+ overflow: hidden;
50
+ line-height: 1.3rem;
51
+ margin-right: 10px; /* Add some space between textarea and button */
52
+ }
53
+
54
+ .ai-terminal-chat-input-container .option {
55
+ width: 21px;
56
+ height: 21px;
57
+ display: inline-block;
58
+ box-sizing: border-box;
59
+ user-select: none;
60
+ background-repeat: no-repeat;
61
+ background-position: center;
62
+ border: var(--theia-border-width) solid transparent;
63
+ opacity: 0.7;
64
+ cursor: pointer;
65
+ }
66
+
67
+ .ai-terminal-chat-input-container .option:hover {
68
+ opacity: 1;
69
+ }
70
+
71
+ @keyframes dots {
72
+ 0%,
73
+ 20% {
74
+ content: "";
75
+ }
76
+ 40% {
77
+ content: ".";
78
+ }
79
+ 60% {
80
+ content: "..";
81
+ }
82
+ 80%,
83
+ 100% {
84
+ content: "...";
85
+ }
86
+ }
87
+ .ai-terminal-chat-result p.loading::after {
88
+ content: "";
89
+ animation: dots 1s steps(1, end) infinite;
90
+ }
91
+
92
+ .ai-terminal-chat-result p.command {
93
+ font-family: "Droid Sans Mono", "monospace", monospace;
94
+ }
@@ -0,0 +1,28 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 EclipseSource GmbH and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ /* note: this bogus test file is required so that
18
+ we are able to run mocha unit tests on this
19
+ package, without having any actual unit tests in it.
20
+ This way a coverage report will be generated,
21
+ showing 0% coverage, instead of no report.
22
+ This file can be removed once we have real unit
23
+ tests in place. */
24
+
25
+ describe('ai-terminal package', () => {
26
+
27
+ it('support code coverage statistics', () => true);
28
+ });