@theia/ai-ide 1.67.0-next.86 → 1.68.0-next.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/lib/browser/ai-configuration/agent-configuration-widget.js +8 -8
- package/lib/browser/ai-configuration/agent-configuration-widget.js.map +1 -1
- package/lib/browser/ai-configuration/mcp-configuration-widget.d.ts.map +1 -1
- package/lib/browser/ai-configuration/mcp-configuration-widget.js +6 -6
- package/lib/browser/ai-configuration/mcp-configuration-widget.js.map +1 -1
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.js +10 -10
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.js.map +1 -1
- package/lib/browser/ai-configuration/token-usage-configuration-widget.js +1 -1
- package/lib/browser/ai-configuration/token-usage-configuration-widget.js.map +1 -1
- package/lib/browser/ai-configuration/tools-configuration-widget.d.ts.map +1 -1
- package/lib/browser/ai-configuration/tools-configuration-widget.js +3 -3
- package/lib/browser/ai-configuration/tools-configuration-widget.js.map +1 -1
- package/lib/browser/default-chat-agent-recommendation-service.d.ts +5 -0
- package/lib/browser/default-chat-agent-recommendation-service.d.ts.map +1 -0
- package/lib/browser/default-chat-agent-recommendation-service.js +47 -0
- package/lib/browser/default-chat-agent-recommendation-service.js.map +1 -0
- package/lib/browser/frontend-module.d.ts.map +1 -1
- package/lib/browser/frontend-module.js +3 -3
- package/lib/browser/frontend-module.js.map +1 -1
- package/lib/browser/ide-chat-welcome-message-provider.d.ts +36 -0
- package/lib/browser/ide-chat-welcome-message-provider.d.ts.map +1 -1
- package/lib/browser/ide-chat-welcome-message-provider.js +204 -1
- package/lib/browser/ide-chat-welcome-message-provider.js.map +1 -1
- package/package.json +21 -21
- package/src/browser/ai-configuration/agent-configuration-widget.tsx +8 -8
- package/src/browser/ai-configuration/mcp-configuration-widget.tsx +6 -6
- package/src/browser/ai-configuration/prompt-fragments-configuration-widget.tsx +10 -10
- package/src/browser/ai-configuration/token-usage-configuration-widget.tsx +1 -1
- package/src/browser/ai-configuration/tools-configuration-widget.tsx +3 -3
- package/src/browser/default-chat-agent-recommendation-service.ts +43 -0
- package/src/browser/frontend-module.ts +6 -7
- package/src/browser/ide-chat-welcome-message-provider.tsx +300 -2
- package/src/browser/style/index.css +177 -12
|
@@ -270,8 +270,8 @@ export class AIPromptFragmentsConfigurationWidget extends ReactWidget {
|
|
|
270
270
|
msg: nls.localize('theia/ai/core/promptFragmentsConfiguration/resetToCustomizationDialogMsg',
|
|
271
271
|
'Are you sure you want to reset the prompt fragment "{0}" to use the {1} customization? This will remove all higher-priority customizations.',
|
|
272
272
|
customization.id, type),
|
|
273
|
-
ok: nls.
|
|
274
|
-
cancel: nls.
|
|
273
|
+
ok: nls.localizeByDefault('Reset'),
|
|
274
|
+
cancel: nls.localizeByDefault('Cancel')
|
|
275
275
|
});
|
|
276
276
|
|
|
277
277
|
const shouldReset = await dialog.open();
|
|
@@ -283,8 +283,8 @@ export class AIPromptFragmentsConfigurationWidget extends ReactWidget {
|
|
|
283
283
|
title: nls.localize('theia/ai/core/promptFragmentsConfiguration/resetToBuiltInDialogTitle', 'Reset to Built-in'),
|
|
284
284
|
msg: nls.localize('theia/ai/core/promptFragmentsConfiguration/resetToBuiltInDialogMsg',
|
|
285
285
|
'Are you sure you want to reset the prompt fragment "{0}" to its built-in version? This will remove all customizations.', customization.id),
|
|
286
|
-
ok: nls.
|
|
287
|
-
cancel: nls.
|
|
286
|
+
ok: nls.localizeByDefault('Reset'),
|
|
287
|
+
cancel: nls.localizeByDefault('Cancel')
|
|
288
288
|
});
|
|
289
289
|
|
|
290
290
|
const shouldReset = await dialog.open();
|
|
@@ -323,8 +323,8 @@ export class AIPromptFragmentsConfigurationWidget extends ReactWidget {
|
|
|
323
323
|
'Are you sure you want to remove the {0} customization for prompt fragment "{1}" ({2})?', type, customization.id, description) :
|
|
324
324
|
nls.localize('theia/ai/core/promptFragmentsConfiguration/removeCustomizationDialogMsg',
|
|
325
325
|
'Are you sure you want to remove the {0} customization for prompt fragment "{1}"?', type, customization.id),
|
|
326
|
-
ok: nls.
|
|
327
|
-
cancel: nls.
|
|
326
|
+
ok: nls.localizeByDefault('Remove'),
|
|
327
|
+
cancel: nls.localizeByDefault('Cancel')
|
|
328
328
|
});
|
|
329
329
|
|
|
330
330
|
const shouldDelete = await dialog.open();
|
|
@@ -342,7 +342,7 @@ export class AIPromptFragmentsConfigurationWidget extends ReactWidget {
|
|
|
342
342
|
msg: nls.localize('theia/ai/core/promptFragmentsConfiguration/resetAllCustomizationsDialogMsg',
|
|
343
343
|
'Are you sure you want to reset all prompt fragments to their built-in versions? This will remove all customizations.'),
|
|
344
344
|
ok: nls.localize('theia/ai/core/promptFragmentsConfiguration/resetAllButton', 'Reset All'),
|
|
345
|
-
cancel: nls.
|
|
345
|
+
cancel: nls.localizeByDefault('Cancel')
|
|
346
346
|
});
|
|
347
347
|
|
|
348
348
|
const shouldReset = await dialog.open();
|
|
@@ -492,7 +492,7 @@ export class AIPromptFragmentsConfigurationWidget extends ReactWidget {
|
|
|
492
492
|
{defaultVariantId === variantId && (
|
|
493
493
|
<span className="badge default-variant"
|
|
494
494
|
title={nls.localize('theia/ai/core/promptFragmentsConfiguration/defaultVariantTitle', 'Default variant')}>
|
|
495
|
-
{nls.
|
|
495
|
+
{nls.localizeByDefault('Default')}
|
|
496
496
|
</span>
|
|
497
497
|
)}
|
|
498
498
|
{selectedVariantId === variantId && (
|
|
@@ -601,7 +601,7 @@ export class AIPromptFragmentsConfigurationWidget extends ReactWidget {
|
|
|
601
601
|
{isActive && (
|
|
602
602
|
<span className="active-indicator"
|
|
603
603
|
title={nls.localize('theia/ai/core/promptFragmentsConfiguration/activeCustomizationTitle', 'Active customization')}>
|
|
604
|
-
{nls.
|
|
604
|
+
{nls.localizeByDefault('Active')}
|
|
605
605
|
</span>
|
|
606
606
|
)}
|
|
607
607
|
</div>
|
|
@@ -695,7 +695,7 @@ const CustomizationTypeBadge: React.FC<CustomizationTypeBadgeProps> = ({ promptF
|
|
|
695
695
|
customizationType + ' ' + nls.localize('theia/ai/core/promptFragmentsConfiguration/customization', 'customization')
|
|
696
696
|
: nls.localize('theia/ai/core/promptFragmentsConfiguration/customizationLabel', 'Customization')}`);
|
|
697
697
|
} else {
|
|
698
|
-
setTypeLabel(nls.
|
|
698
|
+
setTypeLabel(nls.localizeByDefault('Built-in'));
|
|
699
699
|
}
|
|
700
700
|
};
|
|
701
701
|
|
|
@@ -68,7 +68,7 @@ export class AITokenUsageConfigurationWidget extends AITableConfigurationWidget<
|
|
|
68
68
|
|
|
69
69
|
protected formatDate(date?: Date): string {
|
|
70
70
|
if (!date) {
|
|
71
|
-
return nls.
|
|
71
|
+
return nls.localizeByDefault('Never');
|
|
72
72
|
}
|
|
73
73
|
return formatDistanceToNow(date, { addSuffix: true });
|
|
74
74
|
}
|
|
@@ -26,7 +26,7 @@ import { AITableConfigurationWidget, TableColumn } from './base/ai-table-configu
|
|
|
26
26
|
const TOOL_OPTIONS: { value: ToolConfirmationMode, label: string, icon: string }[] = [
|
|
27
27
|
{ value: ToolConfirmationMode.DISABLED, label: nls.localizeByDefault('Disabled'), icon: 'close' },
|
|
28
28
|
{ value: ToolConfirmationMode.CONFIRM, label: nls.localize('theia/ai/ide/toolsConfiguration/toolOptions/confirm/label', 'Confirm'), icon: 'question' },
|
|
29
|
-
{ value: ToolConfirmationMode.ALWAYS_ALLOW, label: nls.
|
|
29
|
+
{ value: ToolConfirmationMode.ALWAYS_ALLOW, label: nls.localizeByDefault('Always Allow'), icon: 'thumbsup' },
|
|
30
30
|
];
|
|
31
31
|
|
|
32
32
|
interface ToolItem {
|
|
@@ -36,7 +36,7 @@ interface ToolItem {
|
|
|
36
36
|
@injectable()
|
|
37
37
|
export class AIToolsConfigurationWidget extends AITableConfigurationWidget<ToolItem> {
|
|
38
38
|
static readonly ID = 'ai-tools-configuration-widget';
|
|
39
|
-
static readonly LABEL = nls.
|
|
39
|
+
static readonly LABEL = nls.localizeByDefault('Tools');
|
|
40
40
|
|
|
41
41
|
@inject(ToolConfirmationManager)
|
|
42
42
|
protected readonly confirmationManager: ToolConfirmationManager;
|
|
@@ -154,7 +154,7 @@ export class AIToolsConfigurationWidget extends AITableConfigurationWidget<ToolI
|
|
|
154
154
|
return [
|
|
155
155
|
{
|
|
156
156
|
id: 'tool-name',
|
|
157
|
-
label: nls.
|
|
157
|
+
label: nls.localizeByDefault('Tool'),
|
|
158
158
|
className: 'tool-name-column',
|
|
159
159
|
renderCell: (item: ToolItem) => <span>{item.name}</span>
|
|
160
160
|
},
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2025 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 { injectable } from '@theia/core/shared/inversify';
|
|
18
|
+
import { ChatAgentRecommendationService, RecommendedAgent } from '@theia/ai-chat/lib/common';
|
|
19
|
+
import { nls } from '@theia/core/lib/common/nls';
|
|
20
|
+
|
|
21
|
+
@injectable()
|
|
22
|
+
export class DefaultChatAgentRecommendationService implements ChatAgentRecommendationService {
|
|
23
|
+
|
|
24
|
+
getRecommendedAgents(): RecommendedAgent[] {
|
|
25
|
+
return [
|
|
26
|
+
{
|
|
27
|
+
id: 'Coder',
|
|
28
|
+
label: nls.localize('theia/ai/chat/agent/coder', 'Coder'),
|
|
29
|
+
description: nls.localize('theia/ai/chat/agent/coder/description', 'Code generation and modification')
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'Architect',
|
|
33
|
+
label: nls.localize('theia/ai/chat/agent/architect', 'Architect'),
|
|
34
|
+
description: nls.localize('theia/ai/chat/agent/architect/description', 'High-level design and architecture')
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'Universal',
|
|
38
|
+
label: nls.localize('theia/ai/chat/agent/universal', 'Universal'),
|
|
39
|
+
description: nls.localize('theia/ai/chat/agent/universal/description', 'General-purpose assistant')
|
|
40
|
+
}
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import '../../src/browser/style/index.css';
|
|
18
18
|
|
|
19
19
|
import { ContainerModule } from '@theia/core/shared/inversify';
|
|
20
|
-
import { ChatAgent,
|
|
20
|
+
import { ChatAgent, ChatAgentRecommendationService } from '@theia/ai-chat/lib/common';
|
|
21
21
|
import { Agent, AIVariableContribution, bindToolProvider } from '@theia/ai-core/lib/common';
|
|
22
22
|
import { ArchitectAgent } from './architect-agent';
|
|
23
23
|
import { CoderAgent } from './coder-agent';
|
|
@@ -60,8 +60,8 @@ import {
|
|
|
60
60
|
DefaultFileChangeSetTitleProvider,
|
|
61
61
|
ReplaceContentInFileFunctionHelperV2
|
|
62
62
|
} from './file-changeset-functions';
|
|
63
|
-
import { OrchestratorChatAgent
|
|
64
|
-
import { UniversalChatAgent
|
|
63
|
+
import { OrchestratorChatAgent } from '../common/orchestrator-chat-agent';
|
|
64
|
+
import { UniversalChatAgent } from '../common/universal-chat-agent';
|
|
65
65
|
import { AppTesterChatAgent } from './app-tester-chat-agent';
|
|
66
66
|
import { GitHubChatAgent } from './github-chat-agent';
|
|
67
67
|
import { CommandChatAgent } from '../common/command-chat-agents';
|
|
@@ -78,6 +78,7 @@ import { TemplatePreferenceContribution } from './template-preference-contributi
|
|
|
78
78
|
import { AIMCPConfigurationWidget } from './ai-configuration/mcp-configuration-widget';
|
|
79
79
|
import { ChatWelcomeMessageProvider } from '@theia/ai-chat-ui/lib/browser/chat-tree-view';
|
|
80
80
|
import { IdeChatWelcomeMessageProvider } from './ide-chat-welcome-message-provider';
|
|
81
|
+
import { DefaultChatAgentRecommendationService } from './default-chat-agent-recommendation-service';
|
|
81
82
|
import { AITokenUsageConfigurationWidget } from './ai-configuration/token-usage-configuration-widget';
|
|
82
83
|
import { TaskContextSummaryVariableContribution } from './task-background-summary-variable';
|
|
83
84
|
import { GitHubRepoVariableContribution } from './github-repo-variable-contribution';
|
|
@@ -149,10 +150,8 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
|
|
|
149
150
|
bind(Agent).toService(CommandChatAgent);
|
|
150
151
|
bind(ChatAgent).toService(CommandChatAgent);
|
|
151
152
|
|
|
152
|
-
bind(
|
|
153
|
-
bind(
|
|
154
|
-
|
|
155
|
-
bind(ChatWelcomeMessageProvider).to(IdeChatWelcomeMessageProvider);
|
|
153
|
+
bind(ChatWelcomeMessageProvider).to(IdeChatWelcomeMessageProvider).inSingletonScope();
|
|
154
|
+
bind(ChatAgentRecommendationService).to(DefaultChatAgentRecommendationService).inSingletonScope();
|
|
156
155
|
|
|
157
156
|
bindToolProvider(GetWorkspaceFileList, bind);
|
|
158
157
|
bindToolProvider(FileContentFunction, bind);
|
|
@@ -17,9 +17,15 @@
|
|
|
17
17
|
import { ChatWelcomeMessageProvider } from '@theia/ai-chat-ui/lib/browser/chat-tree-view';
|
|
18
18
|
import * as React from '@theia/core/shared/react';
|
|
19
19
|
import { nls } from '@theia/core/lib/common/nls';
|
|
20
|
-
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
20
|
+
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
|
|
21
21
|
import { CommonCommands, LocalizedMarkdown, MarkdownRenderer } from '@theia/core/lib/browser';
|
|
22
|
+
import { AlertMessage } from '@theia/core/lib/browser/widgets/alert-message';
|
|
22
23
|
import { OPEN_AI_CONFIG_VIEW } from './ai-configuration/ai-configuration-view-contribution';
|
|
24
|
+
import { CommandRegistry, DisposableCollection, Emitter, Event, PreferenceScope } from '@theia/core';
|
|
25
|
+
import { AgentService, FrontendLanguageModelRegistry } from '@theia/ai-core/lib/common';
|
|
26
|
+
import { PreferenceService } from '@theia/core/lib/common';
|
|
27
|
+
import { DEFAULT_CHAT_AGENT_PREF, BYPASS_MODEL_REQUIREMENT_PREF } from '@theia/ai-chat/lib/common/ai-chat-preferences';
|
|
28
|
+
import { ChatAgentRecommendationService, ChatAgentService } from '@theia/ai-chat/lib/common';
|
|
23
29
|
|
|
24
30
|
const TheiaIdeAiLogo = ({ width = 200, height = 200, className = '' }) =>
|
|
25
31
|
<svg
|
|
@@ -60,8 +66,138 @@ export class IdeChatWelcomeMessageProvider implements ChatWelcomeMessageProvider
|
|
|
60
66
|
@inject(MarkdownRenderer)
|
|
61
67
|
protected readonly markdownRenderer: MarkdownRenderer;
|
|
62
68
|
|
|
69
|
+
@inject(CommandRegistry)
|
|
70
|
+
protected readonly commandRegistry: CommandRegistry;
|
|
71
|
+
|
|
72
|
+
@inject(FrontendLanguageModelRegistry)
|
|
73
|
+
protected languageModelRegistry: FrontendLanguageModelRegistry;
|
|
74
|
+
|
|
75
|
+
@inject(PreferenceService)
|
|
76
|
+
protected preferenceService: PreferenceService;
|
|
77
|
+
|
|
78
|
+
@inject(ChatAgentRecommendationService)
|
|
79
|
+
protected recommendationService: ChatAgentRecommendationService;
|
|
80
|
+
|
|
81
|
+
@inject(ChatAgentService)
|
|
82
|
+
protected chatAgentService: ChatAgentService;
|
|
83
|
+
|
|
84
|
+
@inject(AgentService)
|
|
85
|
+
protected agentService: AgentService;
|
|
86
|
+
|
|
87
|
+
protected readonly toDispose = new DisposableCollection();
|
|
88
|
+
protected _hasReadyModels = false;
|
|
89
|
+
protected _modelRequirementBypassed = false;
|
|
90
|
+
protected _defaultAgent = '';
|
|
91
|
+
protected modelConfig: { hasModels: boolean; errorMessages: string[] } | undefined;
|
|
92
|
+
|
|
93
|
+
protected readonly onStateChangedEmitter = new Emitter<void>();
|
|
94
|
+
|
|
95
|
+
get onStateChanged(): Event<void> {
|
|
96
|
+
return this.onStateChangedEmitter.event;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@postConstruct()
|
|
100
|
+
protected init(): void {
|
|
101
|
+
this.checkLanguageModelStatus();
|
|
102
|
+
this.toDispose.push(
|
|
103
|
+
this.languageModelRegistry.onChange(() => {
|
|
104
|
+
this.checkLanguageModelStatus();
|
|
105
|
+
})
|
|
106
|
+
);
|
|
107
|
+
this.toDispose.push(
|
|
108
|
+
this.preferenceService.onPreferenceChanged(e => {
|
|
109
|
+
if (e.preferenceName === DEFAULT_CHAT_AGENT_PREF) {
|
|
110
|
+
const effectiveValue = this.preferenceService.get<string>(DEFAULT_CHAT_AGENT_PREF, '');
|
|
111
|
+
if (this._defaultAgent !== effectiveValue) {
|
|
112
|
+
this._defaultAgent = effectiveValue;
|
|
113
|
+
this.notifyStateChanged();
|
|
114
|
+
}
|
|
115
|
+
} else if (e.preferenceName === BYPASS_MODEL_REQUIREMENT_PREF) {
|
|
116
|
+
const effectiveValue = this.preferenceService.get<boolean>(BYPASS_MODEL_REQUIREMENT_PREF, false);
|
|
117
|
+
if (this._modelRequirementBypassed !== effectiveValue) {
|
|
118
|
+
this._modelRequirementBypassed = effectiveValue;
|
|
119
|
+
this.notifyStateChanged();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
);
|
|
124
|
+
this.toDispose.push(
|
|
125
|
+
this.agentService.onDidChangeAgents(() => {
|
|
126
|
+
this.notifyStateChanged();
|
|
127
|
+
})
|
|
128
|
+
);
|
|
129
|
+
this.analyzeModelConfiguration().then(config => {
|
|
130
|
+
this.modelConfig = config;
|
|
131
|
+
this.notifyStateChanged();
|
|
132
|
+
});
|
|
133
|
+
this.preferenceService.ready.then(() => {
|
|
134
|
+
const defaultAgentValue = this.preferenceService.get(DEFAULT_CHAT_AGENT_PREF, '');
|
|
135
|
+
const bypassValue = this.preferenceService.get(BYPASS_MODEL_REQUIREMENT_PREF, false);
|
|
136
|
+
this._defaultAgent = defaultAgentValue;
|
|
137
|
+
this._modelRequirementBypassed = bypassValue;
|
|
138
|
+
this.notifyStateChanged();
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
protected async checkLanguageModelStatus(): Promise<void> {
|
|
143
|
+
const models = await this.languageModelRegistry.getLanguageModels();
|
|
144
|
+
this._hasReadyModels = models.some(model => model.status.status === 'ready');
|
|
145
|
+
this.modelConfig = await this.analyzeModelConfiguration();
|
|
146
|
+
this.notifyStateChanged();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
protected async analyzeModelConfiguration(): Promise<{ hasModels: boolean; errorMessages: string[] }> {
|
|
150
|
+
const models = await this.languageModelRegistry.getLanguageModels();
|
|
151
|
+
const hasModels = models.length > 0;
|
|
152
|
+
const unavailableModels = models.filter(model => model.status.status === 'unavailable');
|
|
153
|
+
const errorMessages = unavailableModels
|
|
154
|
+
.map(model => model.status.message)
|
|
155
|
+
.filter((msg): msg is string => !!msg);
|
|
156
|
+
const uniqueErrorMessages = [...new Set(errorMessages)];
|
|
157
|
+
return { hasModels, errorMessages: uniqueErrorMessages };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
protected notifyStateChanged(): void {
|
|
161
|
+
this.onStateChangedEmitter.fire();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
get hasReadyModels(): boolean {
|
|
165
|
+
return this._hasReadyModels;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
get modelRequirementBypassed(): boolean {
|
|
169
|
+
return this._modelRequirementBypassed;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
get defaultAgent(): string {
|
|
173
|
+
return this._defaultAgent;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
protected setModelRequirementBypassed(bypassed: boolean): void {
|
|
177
|
+
this.preferenceService.set(BYPASS_MODEL_REQUIREMENT_PREF, bypassed, PreferenceScope.User);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
protected setDefaultAgent(agentId: string): void {
|
|
181
|
+
this.preferenceService.set(DEFAULT_CHAT_AGENT_PREF, agentId, PreferenceScope.User);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
dispose(): void {
|
|
185
|
+
this.toDispose.dispose();
|
|
186
|
+
this.onStateChangedEmitter.dispose();
|
|
187
|
+
}
|
|
188
|
+
|
|
63
189
|
renderWelcomeMessage(): React.ReactNode {
|
|
64
|
-
|
|
190
|
+
if (!this._hasReadyModels && !this._modelRequirementBypassed) {
|
|
191
|
+
return this.renderModelConfigurationScreen();
|
|
192
|
+
}
|
|
193
|
+
if (!this._defaultAgent) {
|
|
194
|
+
return this.renderAgentSelectionScreen();
|
|
195
|
+
}
|
|
196
|
+
return this.renderWelcomeScreen();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
protected renderWelcomeScreen(): React.ReactNode {
|
|
200
|
+
return <div className={'theia-WelcomeMessage'} key="normal-welcome">
|
|
65
201
|
<TheiaIdeAiLogo width={200} height={200} className="theia-WelcomeMessage-Logo" />
|
|
66
202
|
<LocalizedMarkdown
|
|
67
203
|
localizationKey="theia/ai/ide/chatWelcomeMessage"
|
|
@@ -82,6 +218,168 @@ Lean more in the [documentation](https://theia-ide.org/docs/user_ai/#chat).
|
|
|
82
218
|
</div>;
|
|
83
219
|
}
|
|
84
220
|
|
|
221
|
+
protected renderModelConfigurationScreen(): React.ReactNode {
|
|
222
|
+
const config = this.modelConfig ?? { hasModels: false, errorMessages: [] };
|
|
223
|
+
const { hasModels, errorMessages } = config;
|
|
224
|
+
|
|
225
|
+
if (!hasModels) {
|
|
226
|
+
return <div className={'theia-WelcomeMessage'} key="setup-state">
|
|
227
|
+
<div className="theia-WelcomeMessage-ErrorIcon">⚠️</div>
|
|
228
|
+
<LocalizedMarkdown
|
|
229
|
+
localizationKey="theia/ai/ide/noLanguageModelProviders"
|
|
230
|
+
defaultMarkdown={`
|
|
231
|
+
## No Language Model Providers Available
|
|
232
|
+
|
|
233
|
+
No language model provider packages are installed in this IDE.
|
|
234
|
+
|
|
235
|
+
This typically happens in custom IDE distributions where Theia AI language model packages have been omitted.
|
|
236
|
+
|
|
237
|
+
**To resolve this:**
|
|
238
|
+
|
|
239
|
+
- Install one or more language model provider packages (e.g., '@theia/ai-openai', '@theia/ai-anthropic', '@theia/ai-ollama')
|
|
240
|
+
- Or use agents that don't require Theia Language Models (e.g., Claude Code)
|
|
241
|
+
`}
|
|
242
|
+
markdownRenderer={this.markdownRenderer}
|
|
243
|
+
className="theia-WelcomeMessage-Content"
|
|
244
|
+
/>
|
|
245
|
+
<div className="theia-WelcomeMessage-Actions">
|
|
246
|
+
<button
|
|
247
|
+
className="theia-button main"
|
|
248
|
+
onClick={() => this.setModelRequirementBypassed(true)}>
|
|
249
|
+
{nls.localize('theia/ai/ide/continueAnyway', 'Continue Anyway')}
|
|
250
|
+
</button>
|
|
251
|
+
</div>
|
|
252
|
+
<small className="theia-WelcomeMessage-Hint">
|
|
253
|
+
{nls.localize('theia/ai/ide/bypassHint', 'Some agents like Claude Code don\'t require Theia Language Models')}
|
|
254
|
+
</small>
|
|
255
|
+
</div>;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return <div className={'theia-WelcomeMessage'} key="setup-state">
|
|
259
|
+
<TheiaIdeAiLogo width={150} height={150} className="theia-WelcomeMessage-Logo" />
|
|
260
|
+
<LocalizedMarkdown
|
|
261
|
+
key="configure-provider-hasmodels"
|
|
262
|
+
localizationKey="theia/ai/ide/configureProvider"
|
|
263
|
+
defaultMarkdown={`
|
|
264
|
+
# Please configure at least one language model provider
|
|
265
|
+
|
|
266
|
+
If you want to use [OpenAI]({0}), [Anthropic]({1}) or [GoogleAI]({2}) hosted models, please enter an API key in the settings.
|
|
267
|
+
|
|
268
|
+
If you want to use another provider such as Ollama, please configure it in the settings and adapt agents or a model alias to use your custom model.
|
|
269
|
+
|
|
270
|
+
**Note:** Some agents, such as Claude Code do not need a provider to be configured, just continue in this case.
|
|
271
|
+
|
|
272
|
+
See the [documentation](https://theia-ide.org/docs/user_ai/) for more details.
|
|
273
|
+
`}
|
|
274
|
+
args={[
|
|
275
|
+
`command:${CommonCommands.OPEN_PREFERENCES.id}?ai-features.languageModels.openai`,
|
|
276
|
+
`command:${CommonCommands.OPEN_PREFERENCES.id}?ai-features.languageModels.anthropic`,
|
|
277
|
+
`command:${CommonCommands.OPEN_PREFERENCES.id}?ai-features.languageModels.googleai`
|
|
278
|
+
]}
|
|
279
|
+
markdownRenderer={this.markdownRenderer}
|
|
280
|
+
className="theia-WelcomeMessage-Content"
|
|
281
|
+
markdownOptions={{
|
|
282
|
+
supportHtml: true,
|
|
283
|
+
isTrusted: { enabledCommands: [CommonCommands.OPEN_PREFERENCES.id] }
|
|
284
|
+
}}
|
|
285
|
+
/>
|
|
286
|
+
{errorMessages.length > 0 && (
|
|
287
|
+
<>
|
|
288
|
+
<LocalizedMarkdown
|
|
289
|
+
key="configuration-state"
|
|
290
|
+
localizationKey="theia/ai/ide/configurationState"
|
|
291
|
+
defaultMarkdown="# Current Configuration State"
|
|
292
|
+
markdownRenderer={this.markdownRenderer}
|
|
293
|
+
className="theia-WelcomeMessage-Content"
|
|
294
|
+
/>
|
|
295
|
+
<div className="theia-WelcomeMessage-Content">
|
|
296
|
+
<ul className="theia-WelcomeMessage-IssuesList">
|
|
297
|
+
{errorMessages.map((msg, idx) => <li key={idx}>{msg}</li>)}
|
|
298
|
+
</ul>
|
|
299
|
+
</div>
|
|
300
|
+
</>
|
|
301
|
+
)}
|
|
302
|
+
<div className="theia-WelcomeMessage-Actions">
|
|
303
|
+
<button
|
|
304
|
+
className="theia-button main"
|
|
305
|
+
onClick={() => this.commandRegistry.executeCommand(CommonCommands.OPEN_PREFERENCES.id, 'ai-features')}>
|
|
306
|
+
{nls.localize('theia/ai/ide/openSettings', 'Open AI Settings')}
|
|
307
|
+
</button>
|
|
308
|
+
<button
|
|
309
|
+
className="theia-button secondary"
|
|
310
|
+
onClick={() => this.setModelRequirementBypassed(true)}>
|
|
311
|
+
{nls.localize('theia/ai/ide/continueAnyway', 'Continue Anyway')}
|
|
312
|
+
</button>
|
|
313
|
+
</div>
|
|
314
|
+
<small className="theia-WelcomeMessage-Hint">
|
|
315
|
+
{nls.localize('theia/ai/ide/bypassHint', 'Some agents like Claude Code don\'t require Theia Language Models')}
|
|
316
|
+
</small>
|
|
317
|
+
</div>;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
protected renderAgentSelectionScreen(): React.ReactNode {
|
|
321
|
+
const recommendedAgents = this.recommendationService.getRecommendedAgents()
|
|
322
|
+
.filter(agent => this.chatAgentService.getAgent(agent.id) !== undefined);
|
|
323
|
+
|
|
324
|
+
return <div className={'theia-WelcomeMessage theia-WelcomeMessage-AgentSelection'} key="agent-selection">
|
|
325
|
+
<TheiaIdeAiLogo width={200} height={200} className="theia-WelcomeMessage-Logo" />
|
|
326
|
+
<LocalizedMarkdown
|
|
327
|
+
localizationKey="theia/ai/ide/selectDefaultAgent"
|
|
328
|
+
defaultMarkdown={`
|
|
329
|
+
## Select a Default Chat Agent
|
|
330
|
+
|
|
331
|
+
Choose the agent to use by default. You can always override this by mentioning @AgentName in your message.
|
|
332
|
+
`}
|
|
333
|
+
markdownRenderer={this.markdownRenderer}
|
|
334
|
+
className="theia-WelcomeMessage-Content"
|
|
335
|
+
/>
|
|
336
|
+
{recommendedAgents.length > 0 && (
|
|
337
|
+
<p className="theia-WelcomeMessage-RecommendedNote">
|
|
338
|
+
{nls.localize('theia/ai/ide/recommendedAgents', 'Recommended agents:')}
|
|
339
|
+
</p>
|
|
340
|
+
)}
|
|
341
|
+
{recommendedAgents.length > 0 ? (
|
|
342
|
+
<>
|
|
343
|
+
<div className="theia-WelcomeMessage-AgentButtons">
|
|
344
|
+
{recommendedAgents.map(agent => (
|
|
345
|
+
<button
|
|
346
|
+
key={agent.id}
|
|
347
|
+
className="theia-WelcomeMessage-AgentButton"
|
|
348
|
+
onClick={() => this.setDefaultAgent(agent.id)}
|
|
349
|
+
title={agent.description}>
|
|
350
|
+
<span className="theia-WelcomeMessage-AgentButton-Icon">@</span>
|
|
351
|
+
<span className="theia-WelcomeMessage-AgentButton-Label">{agent.label}</span>
|
|
352
|
+
</button>
|
|
353
|
+
))}
|
|
354
|
+
</div>
|
|
355
|
+
<div className="theia-WelcomeMessage-AlternativeOptions">
|
|
356
|
+
<p className="theia-WelcomeMessage-OrDivider">
|
|
357
|
+
{nls.localize('theia/ai/ide/or', 'or')}
|
|
358
|
+
</p>
|
|
359
|
+
</div>
|
|
360
|
+
</>
|
|
361
|
+
) : (
|
|
362
|
+
<AlertMessage
|
|
363
|
+
type='WARNING'
|
|
364
|
+
header={nls.localize('theia/ai/ide/noRecommendedAgents', 'No recommended agents are available.')}
|
|
365
|
+
/>
|
|
366
|
+
)}
|
|
367
|
+
<AlertMessage
|
|
368
|
+
type='INFO'
|
|
369
|
+
header={recommendedAgents.length > 0
|
|
370
|
+
? nls.localize('theia/ai/ide/moreAgentsAvailable/header', 'More agents are available')
|
|
371
|
+
: nls.localize('theia/ai/ide/configureAgent/header', 'Configure a default agent')}>
|
|
372
|
+
<LocalizedMarkdown
|
|
373
|
+
localizationKey="theia/ai/ide/moreAgentsAvailable"
|
|
374
|
+
defaultMarkdown='Use @AgentName to try others or configure a different default in [preferences]({0}).'
|
|
375
|
+
args={[`command:${CommonCommands.OPEN_PREFERENCES.id}?ai-features.chat`]}
|
|
376
|
+
markdownRenderer={this.markdownRenderer}
|
|
377
|
+
markdownOptions={{ isTrusted: { enabledCommands: [CommonCommands.OPEN_PREFERENCES.id] } }}
|
|
378
|
+
/>
|
|
379
|
+
</AlertMessage>
|
|
380
|
+
</div>;
|
|
381
|
+
}
|
|
382
|
+
|
|
85
383
|
renderDisabledMessage(): React.ReactNode {
|
|
86
384
|
const openAiHistory = 'aiHistory:open';
|
|
87
385
|
|