@theia/ai-core 1.55.1 → 1.57.0-next.112
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 +2 -1
- package/data/prompttemplate.tmLanguage.json +60 -5
- package/lib/browser/ai-configuration/agent-configuration-widget.d.ts.map +1 -1
- package/lib/browser/ai-configuration/agent-configuration-widget.js +10 -5
- package/lib/browser/ai-configuration/agent-configuration-widget.js.map +1 -1
- package/lib/browser/ai-configuration/language-model-renderer.js +1 -1
- package/lib/browser/ai-configuration/language-model-renderer.js.map +1 -1
- package/lib/browser/ai-configuration/template-settings-renderer.d.ts +6 -4
- package/lib/browser/ai-configuration/template-settings-renderer.d.ts.map +1 -1
- package/lib/browser/ai-configuration/template-settings-renderer.js +49 -11
- package/lib/browser/ai-configuration/template-settings-renderer.js.map +1 -1
- package/lib/browser/ai-core-preferences.d.ts +15 -0
- package/lib/browser/ai-core-preferences.d.ts.map +1 -1
- package/lib/browser/ai-core-preferences.js +30 -1
- package/lib/browser/ai-core-preferences.js.map +1 -1
- package/lib/browser/frontend-language-model-registry.d.ts +3 -0
- package/lib/browser/frontend-language-model-registry.d.ts.map +1 -1
- package/lib/browser/frontend-language-model-registry.js +19 -2
- package/lib/browser/frontend-language-model-registry.js.map +1 -1
- package/lib/browser/frontend-prompt-customization-service.d.ts +1 -0
- package/lib/browser/frontend-prompt-customization-service.d.ts.map +1 -1
- package/lib/browser/frontend-prompt-customization-service.js +6 -0
- package/lib/browser/frontend-prompt-customization-service.js.map +1 -1
- package/lib/browser/prompttemplate-contribution.d.ts +2 -2
- package/lib/browser/prompttemplate-contribution.d.ts.map +1 -1
- package/lib/browser/prompttemplate-contribution.js +3 -4
- package/lib/browser/prompttemplate-contribution.js.map +1 -1
- package/lib/common/agent-service.js +1 -1
- package/lib/common/agent-service.js.map +1 -1
- package/lib/common/agent.d.ts +1 -1
- package/lib/common/communication-recording-service.d.ts +5 -2
- package/lib/common/communication-recording-service.d.ts.map +1 -1
- package/lib/common/communication-recording-service.js.map +1 -1
- package/lib/common/language-model-delegate.d.ts +1 -0
- package/lib/common/language-model-delegate.d.ts.map +1 -1
- package/lib/common/language-model-delegate.js.map +1 -1
- package/lib/common/language-model.d.ts +23 -8
- package/lib/common/language-model.d.ts.map +1 -1
- package/lib/common/language-model.js +24 -1
- package/lib/common/language-model.js.map +1 -1
- package/lib/common/prompt-service-util.d.ts +5 -2
- package/lib/common/prompt-service-util.d.ts.map +1 -1
- package/lib/common/prompt-service-util.js +14 -3
- package/lib/common/prompt-service-util.js.map +1 -1
- package/lib/common/prompt-service.d.ts +36 -6
- package/lib/common/prompt-service.d.ts.map +1 -1
- package/lib/common/prompt-service.js +49 -6
- package/lib/common/prompt-service.js.map +1 -1
- package/lib/common/prompt-service.spec.js +176 -8
- package/lib/common/prompt-service.spec.js.map +1 -1
- package/lib/common/settings-service.d.ts +5 -0
- package/lib/common/settings-service.d.ts.map +1 -1
- package/lib/common/tool-invocation-registry.d.ts +33 -0
- package/lib/common/tool-invocation-registry.d.ts.map +1 -1
- package/lib/common/tool-invocation-registry.js +12 -0
- package/lib/common/tool-invocation-registry.js.map +1 -1
- package/lib/node/ai-core-backend-module.d.ts.map +1 -1
- package/lib/node/ai-core-backend-module.js +6 -1
- package/lib/node/ai-core-backend-module.js.map +1 -1
- package/lib/node/language-model-frontend-delegate.d.ts +1 -1
- package/lib/node/language-model-frontend-delegate.d.ts.map +1 -1
- package/lib/node/language-model-frontend-delegate.js +14 -5
- package/lib/node/language-model-frontend-delegate.js.map +1 -1
- package/package.json +11 -11
- package/src/browser/ai-configuration/agent-configuration-widget.tsx +28 -11
- package/src/browser/ai-configuration/language-model-renderer.tsx +1 -1
- package/src/browser/ai-configuration/template-settings-renderer.tsx +105 -16
- package/src/browser/ai-core-preferences.ts +40 -1
- package/src/browser/frontend-language-model-registry.ts +21 -2
- package/src/browser/frontend-prompt-customization-service.ts +8 -0
- package/src/browser/prompttemplate-contribution.ts +6 -7
- package/src/browser/style/index.css +37 -5
- package/src/common/agent-service.ts +1 -1
- package/src/common/agent.ts +1 -1
- package/src/common/communication-recording-service.ts +6 -2
- package/src/common/language-model-delegate.ts +1 -0
- package/src/common/language-model.ts +36 -2
- package/src/common/prompt-service-util.ts +12 -2
- package/src/common/prompt-service.spec.ts +211 -8
- package/src/common/prompt-service.ts +85 -12
- package/src/common/settings-service.ts +5 -0
- package/src/common/tool-invocation-registry.ts +46 -0
- package/src/node/ai-core-backend-module.ts +9 -1
- package/src/node/language-model-frontend-delegate.ts +12 -5
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theia/ai-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.57.0-next.112+f4778c273",
|
|
4
4
|
"description": "Theia - AI Core",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@theia/core": "1.
|
|
7
|
-
"@theia/editor": "1.
|
|
8
|
-
"@theia/filesystem": "1.
|
|
9
|
-
"@theia/monaco": "1.
|
|
10
|
-
"@theia/monaco-editor-core": "1.
|
|
11
|
-
"@theia/output": "1.
|
|
12
|
-
"@theia/variable-resolver": "1.
|
|
13
|
-
"@theia/workspace": "1.
|
|
6
|
+
"@theia/core": "1.57.0-next.112+f4778c273",
|
|
7
|
+
"@theia/editor": "1.57.0-next.112+f4778c273",
|
|
8
|
+
"@theia/filesystem": "1.57.0-next.112+f4778c273",
|
|
9
|
+
"@theia/monaco": "1.57.0-next.112+f4778c273",
|
|
10
|
+
"@theia/monaco-editor-core": "1.96.302",
|
|
11
|
+
"@theia/output": "1.57.0-next.112+f4778c273",
|
|
12
|
+
"@theia/variable-resolver": "1.57.0-next.112+f4778c273",
|
|
13
|
+
"@theia/workspace": "1.57.0-next.112+f4778c273",
|
|
14
14
|
"@types/js-yaml": "^4.0.9",
|
|
15
15
|
"js-yaml": "^4.1.0",
|
|
16
16
|
"minimatch": "^5.1.0",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"watch": "theiaext watch"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@theia/ext-scripts": "1.
|
|
55
|
+
"@theia/ext-scripts": "1.58.0"
|
|
56
56
|
},
|
|
57
57
|
"nyc": {
|
|
58
58
|
"extends": "../../configs/nyc.json"
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "f4778c2737bb75613f0e1f99da8996bad91f6e17"
|
|
61
61
|
}
|
|
@@ -23,8 +23,8 @@ import {
|
|
|
23
23
|
AIVariableService,
|
|
24
24
|
LanguageModel,
|
|
25
25
|
LanguageModelRegistry,
|
|
26
|
+
matchVariablesRegEx,
|
|
26
27
|
PROMPT_FUNCTION_REGEX,
|
|
27
|
-
PROMPT_VARIABLE_REGEX,
|
|
28
28
|
PromptCustomizationService,
|
|
29
29
|
PromptService,
|
|
30
30
|
} from '../../common';
|
|
@@ -112,7 +112,7 @@ export class AIAgentConfigurationWidget extends ReactWidget {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
private renderAgentName(agent: Agent): React.ReactNode {
|
|
115
|
-
const tagsSuffix = agent.tags?.length ? <span>{agent.tags.map(tag => <span className='agent-tag'>{tag}</span>)}</span> : '';
|
|
115
|
+
const tagsSuffix = agent.tags?.length ? <span>{agent.tags.map(tag => <span key={tag} className='agent-tag'>{tag}</span>)}</span> : '';
|
|
116
116
|
return <span>{agent.name} {tagsSuffix}</span>;
|
|
117
117
|
}
|
|
118
118
|
|
|
@@ -137,14 +137,31 @@ export class AIAgentConfigurationWidget extends ReactWidget {
|
|
|
137
137
|
Enable Agent
|
|
138
138
|
</label>
|
|
139
139
|
</div>
|
|
140
|
-
<div className=
|
|
141
|
-
|
|
142
|
-
<TemplateRenderer
|
|
143
|
-
key={agent?.id + '.' + template.id}
|
|
144
|
-
agentId={agent.id}
|
|
145
|
-
template={template}
|
|
146
|
-
promptCustomizationService={this.promptCustomizationService} />)}
|
|
140
|
+
<div className="settings-section-subcategory-title ai-settings-section-subcategory-title">
|
|
141
|
+
Prompt Templates
|
|
147
142
|
</div>
|
|
143
|
+
<div className="ai-templates">
|
|
144
|
+
{(() => {
|
|
145
|
+
const defaultTemplates = agent.promptTemplates?.filter(template => !template.variantOf) || [];
|
|
146
|
+
return defaultTemplates.length > 0 ? (
|
|
147
|
+
defaultTemplates.map(template => (
|
|
148
|
+
<div key={agent.id + '.' + template.id}>
|
|
149
|
+
<TemplateRenderer
|
|
150
|
+
key={agent.id + '.' + template.id}
|
|
151
|
+
agentId={agent.id}
|
|
152
|
+
template={template}
|
|
153
|
+
promptService={this.promptService}
|
|
154
|
+
aiSettingsService={this.aiSettingsService}
|
|
155
|
+
promptCustomizationService={this.promptCustomizationService}
|
|
156
|
+
/>
|
|
157
|
+
</div>
|
|
158
|
+
))
|
|
159
|
+
) : (
|
|
160
|
+
<div>No default template available</div>
|
|
161
|
+
);
|
|
162
|
+
})()}
|
|
163
|
+
</div>
|
|
164
|
+
|
|
148
165
|
<div className='ai-lm-requirements'>
|
|
149
166
|
<LanguageModelRenderer
|
|
150
167
|
agent={agent}
|
|
@@ -180,9 +197,9 @@ export class AIAgentConfigurationWidget extends ReactWidget {
|
|
|
180
197
|
const promptTemplates = agent.promptTemplates;
|
|
181
198
|
const result: ParsedPrompt = { functions: [], globalVariables: [], agentSpecificVariables: [] };
|
|
182
199
|
promptTemplates.forEach(template => {
|
|
183
|
-
const storedPrompt = this.promptService.
|
|
200
|
+
const storedPrompt = this.promptService.getUnresolvedPrompt(template.id);
|
|
184
201
|
const prompt = storedPrompt?.template ?? template.template;
|
|
185
|
-
const variableMatches =
|
|
202
|
+
const variableMatches = matchVariablesRegEx(prompt);
|
|
186
203
|
|
|
187
204
|
variableMatches.forEach(match => {
|
|
188
205
|
const variableId = match[1];
|
|
@@ -99,7 +99,7 @@ export const LanguageModelRenderer: React.FC<LanguageModelSettingsProps> = (
|
|
|
99
99
|
onChange={event => onSelectedModelChange(requirements.purpose, event)}
|
|
100
100
|
>
|
|
101
101
|
<option value=""></option>
|
|
102
|
-
{languageModels?.map(model => (
|
|
102
|
+
{languageModels?.sort((a, b) => (a.name ?? a.id).localeCompare(b.name ?? b.id)).map(model => (
|
|
103
103
|
<option key={model.id} value={model.id}>{model.name ?? model.id}</option>
|
|
104
104
|
))}
|
|
105
105
|
</select>
|
|
@@ -14,26 +14,115 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
import * as React from '@theia/core/shared/react';
|
|
17
|
-
import { PromptCustomizationService } from '../../common/prompt-service';
|
|
18
|
-
import { PromptTemplate } from '../../common';
|
|
17
|
+
import { PromptCustomizationService, PromptService } from '../../common/prompt-service';
|
|
18
|
+
import { AISettingsService, PromptTemplate } from '../../common';
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
const DEFAULT_VARIANT = 'default';
|
|
21
|
+
|
|
22
|
+
export interface TemplateRendererProps {
|
|
21
23
|
agentId: string;
|
|
22
24
|
template: PromptTemplate;
|
|
23
25
|
promptCustomizationService: PromptCustomizationService;
|
|
26
|
+
promptService: PromptService;
|
|
27
|
+
aiSettingsService: AISettingsService;
|
|
24
28
|
}
|
|
25
29
|
|
|
26
|
-
export const TemplateRenderer: React.FC<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
export const TemplateRenderer: React.FC<TemplateRendererProps> = ({
|
|
31
|
+
agentId,
|
|
32
|
+
template,
|
|
33
|
+
promptCustomizationService,
|
|
34
|
+
promptService,
|
|
35
|
+
aiSettingsService,
|
|
36
|
+
}) => {
|
|
37
|
+
const variantIds = [DEFAULT_VARIANT, ...promptService.getVariantIds(template.id)];
|
|
38
|
+
const [selectedVariant, setSelectedVariant] = React.useState<string>(DEFAULT_VARIANT);
|
|
39
|
+
|
|
40
|
+
React.useEffect(() => {
|
|
41
|
+
(async () => {
|
|
42
|
+
const agentSettings = await aiSettingsService.getAgentSettings(agentId);
|
|
43
|
+
const currentVariant =
|
|
44
|
+
agentSettings?.selectedVariants?.[template.id] || DEFAULT_VARIANT;
|
|
45
|
+
setSelectedVariant(currentVariant);
|
|
46
|
+
})();
|
|
47
|
+
}, [template.id, aiSettingsService, agentId]);
|
|
48
|
+
|
|
49
|
+
const isInvalidVariant = !variantIds.includes(selectedVariant);
|
|
50
|
+
|
|
51
|
+
const handleVariantChange = async (event: React.ChangeEvent<HTMLSelectElement>) => {
|
|
52
|
+
const newVariant = event.target.value;
|
|
53
|
+
setSelectedVariant(newVariant);
|
|
54
|
+
|
|
55
|
+
const agentSettings = await aiSettingsService.getAgentSettings(agentId);
|
|
56
|
+
const selectedVariants = agentSettings?.selectedVariants || {};
|
|
57
|
+
|
|
58
|
+
const updatedVariants = { ...selectedVariants };
|
|
59
|
+
if (newVariant === DEFAULT_VARIANT) {
|
|
60
|
+
delete updatedVariants[template.id];
|
|
61
|
+
} else {
|
|
62
|
+
updatedVariants[template.id] = newVariant;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
await aiSettingsService.updateAgentSettings(agentId, {
|
|
66
|
+
selectedVariants: updatedVariants,
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const openTemplate = () => {
|
|
71
|
+
const templateId = selectedVariant === DEFAULT_VARIANT ? template.id : selectedVariant;
|
|
72
|
+
const selectedTemplate = promptService.getRawPrompt(templateId);
|
|
73
|
+
promptCustomizationService.editTemplate(templateId, selectedTemplate?.template || '');
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const resetTemplate = () => {
|
|
77
|
+
const templateId = selectedVariant === DEFAULT_VARIANT ? template.id : selectedVariant;
|
|
78
|
+
promptCustomizationService.resetTemplate(templateId);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div className="template-renderer">
|
|
83
|
+
<div className="settings-section-title template-header">
|
|
84
|
+
<strong>{template.id}</strong>
|
|
85
|
+
</div>
|
|
86
|
+
<div className="template-controls">
|
|
87
|
+
{(variantIds.length > 1 || isInvalidVariant) && (
|
|
88
|
+
<>
|
|
89
|
+
<label htmlFor={`variant-selector-${template.id}`} className="template-select-label">
|
|
90
|
+
Select Variant:
|
|
91
|
+
</label>
|
|
92
|
+
<select
|
|
93
|
+
id={`variant-selector-${template.id}`}
|
|
94
|
+
className={`theia-select template-variant-selector ${isInvalidVariant ? 'error' : ''}`}
|
|
95
|
+
value={isInvalidVariant ? 'invalid' : selectedVariant}
|
|
96
|
+
onChange={handleVariantChange}
|
|
97
|
+
>
|
|
98
|
+
{isInvalidVariant && (
|
|
99
|
+
<option value="invalid" disabled>
|
|
100
|
+
The selected variant is no longer available
|
|
101
|
+
</option>
|
|
102
|
+
)}
|
|
103
|
+
{variantIds.map(variantId => (
|
|
104
|
+
<option key={variantId} value={variantId}>
|
|
105
|
+
{variantId}
|
|
106
|
+
</option>
|
|
107
|
+
))}
|
|
108
|
+
</select>
|
|
109
|
+
</>
|
|
110
|
+
)}
|
|
111
|
+
<button
|
|
112
|
+
className="theia-button main"
|
|
113
|
+
onClick={openTemplate}
|
|
114
|
+
disabled={isInvalidVariant}
|
|
115
|
+
>
|
|
116
|
+
Edit
|
|
117
|
+
</button>
|
|
118
|
+
<button
|
|
119
|
+
className="theia-button secondary"
|
|
120
|
+
onClick={resetTemplate}
|
|
121
|
+
disabled={isInvalidVariant}
|
|
122
|
+
>
|
|
123
|
+
Reset
|
|
124
|
+
</button>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
39
128
|
};
|
|
@@ -21,6 +21,7 @@ import { interfaces } from '@theia/core/shared/inversify';
|
|
|
21
21
|
export const AI_CORE_PREFERENCES_TITLE = '✨ AI Features [Experimental]';
|
|
22
22
|
export const PREFERENCE_NAME_ENABLE_EXPERIMENTAL = 'ai-features.AiEnable.enableAI';
|
|
23
23
|
export const PREFERENCE_NAME_PROMPT_TEMPLATES = 'ai-features.promptTemplates.promptTemplatesFolder';
|
|
24
|
+
export const PREFERENCE_NAME_REQUEST_SETTINGS = 'ai-features.modelSettings.requestSettings';
|
|
24
25
|
|
|
25
26
|
export const aiCorePreferenceSchema: PreferenceSchema = {
|
|
26
27
|
type: 'object',
|
|
@@ -55,13 +56,51 @@ export const aiCorePreferenceSchema: PreferenceSchema = {
|
|
|
55
56
|
canSelectMany: false
|
|
56
57
|
}
|
|
57
58
|
},
|
|
58
|
-
|
|
59
|
+
},
|
|
60
|
+
[PREFERENCE_NAME_REQUEST_SETTINGS]: {
|
|
61
|
+
title: 'Custom Request Settings',
|
|
62
|
+
markdownDescription: 'Allows specifying custom request settings for multiple models.\n\
|
|
63
|
+
Each object represents the configuration for a specific model. The `modelId` field specifies the model ID, `requestSettings` defines model-specific settings.\n\
|
|
64
|
+
The `providerId` field is optional and allows you to apply the settings to a specific provider. If not set, the settings will be applied to all providers.\n\
|
|
65
|
+
Example providerIds: huggingface, openai, ollama, llamafile.\n\
|
|
66
|
+
Refer to [our documentation](https://theia-ide.org/docs/user_ai/#custom-request-settings) for more information.',
|
|
67
|
+
type: 'array',
|
|
68
|
+
items: {
|
|
69
|
+
type: 'object',
|
|
70
|
+
properties: {
|
|
71
|
+
modelId: {
|
|
72
|
+
type: 'string',
|
|
73
|
+
description: 'The model id'
|
|
74
|
+
},
|
|
75
|
+
requestSettings: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
additionalProperties: true,
|
|
78
|
+
description: 'Settings for the specific model ID.',
|
|
79
|
+
},
|
|
80
|
+
providerId: {
|
|
81
|
+
type: 'string',
|
|
82
|
+
description: 'The (optional) provider id to apply the settings to. If not set, the settings will be applied to all providers.',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
default: [],
|
|
59
87
|
}
|
|
60
88
|
}
|
|
61
89
|
};
|
|
62
90
|
export interface AICoreConfiguration {
|
|
63
91
|
[PREFERENCE_NAME_ENABLE_EXPERIMENTAL]: boolean | undefined;
|
|
64
92
|
[PREFERENCE_NAME_PROMPT_TEMPLATES]: string | undefined;
|
|
93
|
+
[PREFERENCE_NAME_REQUEST_SETTINGS]: Array<{
|
|
94
|
+
modelId: string;
|
|
95
|
+
requestSettings?: { [key: string]: unknown };
|
|
96
|
+
providerId?: string;
|
|
97
|
+
}> | undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface RequestSetting {
|
|
101
|
+
modelId: string;
|
|
102
|
+
requestSettings?: { [key: string]: unknown };
|
|
103
|
+
providerId?: string;
|
|
65
104
|
}
|
|
66
105
|
|
|
67
106
|
export const AICorePreferences = Symbol('AICorePreferences');
|
|
@@ -61,6 +61,10 @@ export class LanguageModelDelegateClientImpl
|
|
|
61
61
|
return this.receiver.toolCall(requestId, toolId, args_string);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
error(id: string, error: Error): void {
|
|
65
|
+
this.receiver.error(id, error);
|
|
66
|
+
}
|
|
67
|
+
|
|
64
68
|
languageModelAdded(metadata: LanguageModelMetaData): void {
|
|
65
69
|
this.receiver.languageModelAdded(metadata);
|
|
66
70
|
}
|
|
@@ -74,6 +78,7 @@ interface StreamState {
|
|
|
74
78
|
id: string;
|
|
75
79
|
tokens: (LanguageModelStreamResponsePart | undefined)[];
|
|
76
80
|
resolve?: (_: unknown) => void;
|
|
81
|
+
reject?: (_: unknown) => void;
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
@injectable()
|
|
@@ -249,8 +254,9 @@ export class FrontendLanguageModelRegistryImpl
|
|
|
249
254
|
yield token;
|
|
250
255
|
}
|
|
251
256
|
} else {
|
|
252
|
-
await new Promise(resolve => {
|
|
257
|
+
await new Promise((resolve, reject) => {
|
|
253
258
|
state.resolve = resolve;
|
|
259
|
+
state.reject = reject;
|
|
254
260
|
});
|
|
255
261
|
}
|
|
256
262
|
}
|
|
@@ -286,6 +292,19 @@ export class FrontendLanguageModelRegistryImpl
|
|
|
286
292
|
throw new Error(`Could not find a tool for ${toolId}!`);
|
|
287
293
|
}
|
|
288
294
|
|
|
295
|
+
// called by backend via the "delegate client" with the error to use for rejection
|
|
296
|
+
error(id: string, error: Error): void {
|
|
297
|
+
if (!this.streams.has(id)) {
|
|
298
|
+
const newStreamState = {
|
|
299
|
+
id,
|
|
300
|
+
tokens: [],
|
|
301
|
+
};
|
|
302
|
+
this.streams.set(id, newStreamState);
|
|
303
|
+
}
|
|
304
|
+
const streamState = this.streams.get(id)!;
|
|
305
|
+
streamState.reject?.(error);
|
|
306
|
+
}
|
|
307
|
+
|
|
289
308
|
override async selectLanguageModels(request: LanguageModelSelector): Promise<LanguageModel[]> {
|
|
290
309
|
await this.initialized;
|
|
291
310
|
const userSettings = (await this.settingsService.getAgentSettings(request.agent))?.languageModelRequirements?.find(req => req.purpose === request.purpose);
|
|
@@ -347,7 +366,7 @@ const languageModelOutputHandler = (
|
|
|
347
366
|
'Sending request:'
|
|
348
367
|
);
|
|
349
368
|
const formattedRequest = formatJsonWithIndentation(args[0]);
|
|
350
|
-
|
|
369
|
+
outputChannel.append(formattedRequest.join('\n'));
|
|
351
370
|
if (args[1]) {
|
|
352
371
|
args[1] = new Proxy(args[1], {
|
|
353
372
|
get<CK extends keyof CancellationToken>(
|
|
@@ -116,6 +116,10 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati
|
|
|
116
116
|
}));
|
|
117
117
|
|
|
118
118
|
this.onDidChangeCustomAgentsEmitter.fire();
|
|
119
|
+
|
|
120
|
+
if (!(await this.fileService.exists(templateURI))) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
119
123
|
const stat = await this.fileService.resolve(templateURI);
|
|
120
124
|
if (stat.children === undefined) {
|
|
121
125
|
return;
|
|
@@ -165,6 +169,10 @@ export class FrontendPromptCustomizationServiceImpl implements PromptCustomizati
|
|
|
165
169
|
return this.templates.get(id);
|
|
166
170
|
}
|
|
167
171
|
|
|
172
|
+
getCustomPromptTemplateIDs(): string[] {
|
|
173
|
+
return Array.from(this.templates.keys());
|
|
174
|
+
}
|
|
175
|
+
|
|
168
176
|
async editTemplate(id: string, defaultContent?: string): Promise<void> {
|
|
169
177
|
const editorUri = await this.getTemplateURI(id);
|
|
170
178
|
if (! await this.fileService.exists(editorUri)) {
|
|
@@ -14,15 +14,15 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import { inject, injectable
|
|
17
|
+
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
18
18
|
import { GrammarDefinition, GrammarDefinitionProvider, LanguageGrammarDefinitionContribution, TextmateRegistry } from '@theia/monaco/lib/browser/textmate';
|
|
19
19
|
import * as monaco from '@theia/monaco-editor-core';
|
|
20
|
-
import { Command, CommandContribution, CommandRegistry,
|
|
20
|
+
import { Command, CommandContribution, CommandRegistry, MessageService } from '@theia/core';
|
|
21
21
|
import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
|
22
22
|
|
|
23
23
|
import { codicon, Widget } from '@theia/core/lib/browser';
|
|
24
24
|
import { EditorWidget, ReplaceOperation } from '@theia/editor/lib/browser';
|
|
25
|
-
import { PromptCustomizationService, PromptService,
|
|
25
|
+
import { PromptCustomizationService, PromptService, ToolInvocationRegistry } from '../common';
|
|
26
26
|
import { ProviderResult } from '@theia/monaco-editor-core/esm/vs/editor/common/languages';
|
|
27
27
|
|
|
28
28
|
const PROMPT_TEMPLATE_LANGUAGE_ID = 'theia-ai-prompt-template';
|
|
@@ -56,9 +56,8 @@ export class PromptTemplateContribution implements LanguageGrammarDefinitionCont
|
|
|
56
56
|
@inject(PromptCustomizationService)
|
|
57
57
|
protected readonly customizationService: PromptCustomizationService;
|
|
58
58
|
|
|
59
|
-
@inject(
|
|
60
|
-
|
|
61
|
-
private toolProviders: ContributionProvider<ToolProvider>;
|
|
59
|
+
@inject(ToolInvocationRegistry)
|
|
60
|
+
protected readonly toolInvocationRegistry: ToolInvocationRegistry;
|
|
62
61
|
|
|
63
62
|
readonly config: monaco.languages.LanguageConfiguration =
|
|
64
63
|
{
|
|
@@ -115,7 +114,7 @@ export class PromptTemplateContribution implements LanguageGrammarDefinitionCont
|
|
|
115
114
|
model,
|
|
116
115
|
position,
|
|
117
116
|
'~{',
|
|
118
|
-
this.
|
|
117
|
+
this.toolInvocationRegistry.getAllFunctions(),
|
|
119
118
|
monaco.languages.CompletionItemKind.Function,
|
|
120
119
|
tool => tool.id,
|
|
121
120
|
tool => tool.name,
|
|
@@ -14,12 +14,44 @@
|
|
|
14
14
|
margin-left: var(--theia-ui-padding);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
.theia-settings-container .settings-section-subcategory-title.ai-settings-section-subcategory-title {
|
|
18
|
+
padding-left: 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
17
21
|
.ai-templates {
|
|
18
|
-
display:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
gap: 5px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.template-renderer {
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
padding: 10px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.template-header {
|
|
34
|
+
margin-bottom: 8px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.template-controls {
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
gap: 10px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.template-select-label {
|
|
44
|
+
margin-right: 5px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.template-variant-selector {
|
|
48
|
+
min-width: 120px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.template-variant-selector.error {
|
|
52
|
+
border-color: var(--theia-errorForeground);
|
|
53
|
+
background-color: var(--theia-errorBackground, rgba(255, 0, 0, 0.1));
|
|
54
|
+
color: var(--theia-errorForeground);
|
|
23
55
|
}
|
|
24
56
|
|
|
25
57
|
#ai-variable-configuration-container-widget,
|
|
@@ -99,7 +99,7 @@ export class AgentServiceImpl implements AgentService {
|
|
|
99
99
|
registerAgent(agent: Agent): void {
|
|
100
100
|
this._agents.push(agent);
|
|
101
101
|
agent.promptTemplates.forEach(
|
|
102
|
-
template => this.promptService.
|
|
102
|
+
template => this.promptService.storePromptTemplate(template)
|
|
103
103
|
);
|
|
104
104
|
this.onDidChangeAgentsEmitter.fire();
|
|
105
105
|
}
|
package/src/common/agent.ts
CHANGED
|
@@ -60,7 +60,7 @@ export interface Agent {
|
|
|
60
60
|
readonly languageModelRequirements: LanguageModelRequirement[];
|
|
61
61
|
|
|
62
62
|
/** A list of tags to filter agents and to display capabilities in the UI */
|
|
63
|
-
readonly tags?:
|
|
63
|
+
readonly tags?: string[];
|
|
64
64
|
|
|
65
65
|
/** The list of local variable identifiers this agent needs to clarify its context requirements. */
|
|
66
66
|
readonly agentSpecificVariables: AgentSpecificVariables[];
|
|
@@ -26,18 +26,22 @@ export interface CommunicationHistoryEntry {
|
|
|
26
26
|
request?: string;
|
|
27
27
|
response?: string;
|
|
28
28
|
responseTime?: number;
|
|
29
|
+
systemMessage?: string;
|
|
29
30
|
messages?: unknown[];
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
export type CommunicationRequestEntry = Omit<CommunicationHistoryEntry, 'response' | 'responseTime'>;
|
|
33
34
|
export type CommunicationResponseEntry = Omit<CommunicationHistoryEntry, 'request'>;
|
|
34
35
|
|
|
36
|
+
export type CommunicationRequestEntryParam = Omit<CommunicationRequestEntry, 'timestamp'> & Partial<Pick<CommunicationHistoryEntry, 'timestamp'>>;
|
|
37
|
+
export type CommunicationResponseEntryParam = Omit<CommunicationResponseEntry, 'timestamp'> & Partial<Pick<CommunicationHistoryEntry, 'timestamp'>>;
|
|
38
|
+
|
|
35
39
|
export const CommunicationRecordingService = Symbol('CommunicationRecordingService');
|
|
36
40
|
export interface CommunicationRecordingService {
|
|
37
|
-
recordRequest(requestEntry:
|
|
41
|
+
recordRequest(requestEntry: CommunicationRequestEntryParam): void;
|
|
38
42
|
readonly onDidRecordRequest: Event<CommunicationRequestEntry>;
|
|
39
43
|
|
|
40
|
-
recordResponse(responseEntry:
|
|
44
|
+
recordResponse(responseEntry: CommunicationResponseEntryParam): void;
|
|
41
45
|
readonly onDidRecordResponse: Event<CommunicationResponseEntry>;
|
|
42
46
|
|
|
43
47
|
getHistory(agentId: string): CommunicationHistory;
|
|
@@ -21,6 +21,7 @@ export const LanguageModelDelegateClient = Symbol('LanguageModelDelegateClient')
|
|
|
21
21
|
export interface LanguageModelDelegateClient {
|
|
22
22
|
toolCall(requestId: string, toolId: string, args_string: string): Promise<unknown>;
|
|
23
23
|
send(id: string, token: LanguageModelStreamResponsePart | undefined): void;
|
|
24
|
+
error(id: string, error: Error): void;
|
|
24
25
|
}
|
|
25
26
|
export const LanguageModelRegistryFrontendDelegate = Symbol('LanguageModelRegistryFrontendDelegate');
|
|
26
27
|
export interface LanguageModelRegistryFrontendDelegate {
|
|
@@ -32,13 +32,42 @@ export const isLanguageModelRequestMessage = (obj: unknown): obj is LanguageMode
|
|
|
32
32
|
'query' in obj &&
|
|
33
33
|
typeof (obj as { query: unknown }).query === 'string'
|
|
34
34
|
);
|
|
35
|
+
export type ToolRequestParametersProperties = Record<string, { type: string, [key: string]: unknown }>;
|
|
36
|
+
export interface ToolRequestParameters {
|
|
37
|
+
type?: 'object';
|
|
38
|
+
properties: ToolRequestParametersProperties;
|
|
39
|
+
required?: string[];
|
|
40
|
+
}
|
|
35
41
|
export interface ToolRequest {
|
|
36
42
|
id: string;
|
|
37
43
|
name: string;
|
|
38
|
-
parameters?:
|
|
44
|
+
parameters?: ToolRequestParameters
|
|
39
45
|
description?: string;
|
|
40
|
-
handler: (arg_string: string) => Promise<unknown>;
|
|
46
|
+
handler: (arg_string: string, ctx?: unknown) => Promise<unknown>;
|
|
47
|
+
providerName?: string;
|
|
41
48
|
}
|
|
49
|
+
|
|
50
|
+
export namespace ToolRequest {
|
|
51
|
+
export function isToolRequestParametersProperties(obj: unknown): obj is ToolRequestParametersProperties {
|
|
52
|
+
if (!obj || typeof obj !== 'object') { return false; };
|
|
53
|
+
|
|
54
|
+
return Object.entries(obj).every(([key, value]) =>
|
|
55
|
+
typeof key === 'string' &&
|
|
56
|
+
value &&
|
|
57
|
+
typeof value === 'object' &&
|
|
58
|
+
'type' in value &&
|
|
59
|
+
typeof value.type === 'string' &&
|
|
60
|
+
Object.keys(value).every(k => typeof k === 'string')
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
export function isToolRequestParameters(obj: unknown): obj is ToolRequestParameters {
|
|
64
|
+
return !!obj && typeof obj === 'object' &&
|
|
65
|
+
(!('type' in obj) || obj.type === 'object') &&
|
|
66
|
+
'properties' in obj && isToolRequestParametersProperties(obj.properties) &&
|
|
67
|
+
(!('required' in obj) || (Array.isArray(obj.required) && obj.required.every(prop => typeof prop === 'string')));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
42
71
|
export interface LanguageModelRequest {
|
|
43
72
|
messages: LanguageModelRequestMessage[],
|
|
44
73
|
tools?: ToolRequest[];
|
|
@@ -107,6 +136,11 @@ export interface LanguageModelMetaData {
|
|
|
107
136
|
readonly family?: string;
|
|
108
137
|
readonly maxInputTokens?: number;
|
|
109
138
|
readonly maxOutputTokens?: number;
|
|
139
|
+
/**
|
|
140
|
+
* Default request settings for the language model. These settings can be set by a user preferences.
|
|
141
|
+
* Settings in a request will override these default settings.
|
|
142
|
+
*/
|
|
143
|
+
readonly defaultRequestSettings?: { [key: string]: unknown };
|
|
110
144
|
}
|
|
111
145
|
|
|
112
146
|
export namespace LanguageModelMetaData {
|
|
@@ -14,8 +14,18 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
/** Should match the one from VariableResolverService. The format is `{{variableName:arg}}`. */
|
|
18
|
-
export const
|
|
17
|
+
/** Should match the one from VariableResolverService. The format is `{{variableName:arg}}`. We allow {{}} and {{{}}} but no mixtures */
|
|
18
|
+
export const PROMPT_VARIABLE_TWO_BRACES_REGEX = /(?<!\{)\{\{\s*([^{}]+?)\s*\}\}(?!\})/g;
|
|
19
|
+
export const PROMPT_VARIABLE_THREE_BRACES_REGEX = /(?<!\{)\{\{\{\s*([^{}]+?)\s*\}\}\}(?!\})/g;
|
|
20
|
+
export function matchVariablesRegEx(template: string): RegExpMatchArray[] {
|
|
21
|
+
const twoBraceMatches = [...template.matchAll(PROMPT_VARIABLE_TWO_BRACES_REGEX)];
|
|
22
|
+
const threeBraceMatches = [...template.matchAll(PROMPT_VARIABLE_THREE_BRACES_REGEX)];
|
|
23
|
+
return twoBraceMatches.concat(threeBraceMatches);
|
|
24
|
+
}
|
|
19
25
|
|
|
20
26
|
/** Match function/tool references in the prompt. The format is `~{functionId}`. */
|
|
21
27
|
export const PROMPT_FUNCTION_REGEX = /\~\{\s*(.*?)\s*\}/g;
|
|
28
|
+
|
|
29
|
+
export function matchFunctionsRegEx(template: string): RegExpMatchArray[] {
|
|
30
|
+
return [...template.matchAll(PROMPT_FUNCTION_REGEX)];
|
|
31
|
+
}
|