@theia/ai-core 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 +30 -0
- package/data/prompttemplate.tmLanguage.json +52 -0
- package/lib/browser/ai-activation-service.d.ts +17 -0
- package/lib/browser/ai-activation-service.d.ts.map +1 -0
- package/lib/browser/ai-activation-service.js +63 -0
- package/lib/browser/ai-activation-service.js.map +1 -0
- package/lib/browser/ai-command-handler-factory.d.ts +4 -0
- package/lib/browser/ai-command-handler-factory.d.ts.map +1 -0
- package/lib/browser/ai-command-handler-factory.js +20 -0
- package/lib/browser/ai-command-handler-factory.js.map +1 -0
- package/lib/browser/ai-configuration/agent-configuration-widget.d.ts +27 -0
- package/lib/browser/ai-configuration/agent-configuration-widget.d.ts.map +1 -0
- package/lib/browser/ai-configuration/agent-configuration-widget.js +231 -0
- package/lib/browser/ai-configuration/agent-configuration-widget.js.map +1 -0
- package/lib/browser/ai-configuration/ai-configuration-service.d.ts +13 -0
- package/lib/browser/ai-configuration/ai-configuration-service.d.ts.map +1 -0
- package/lib/browser/ai-configuration/ai-configuration-service.js +44 -0
- package/lib/browser/ai-configuration/ai-configuration-service.js.map +1 -0
- package/lib/browser/ai-configuration/ai-configuration-view-contribution.d.ts +12 -0
- package/lib/browser/ai-configuration/ai-configuration-view-contribution.d.ts.map +1 -0
- package/lib/browser/ai-configuration/ai-configuration-view-contribution.js +41 -0
- package/lib/browser/ai-configuration/ai-configuration-view-contribution.js.map +1 -0
- package/lib/browser/ai-configuration/ai-configuration-widget.d.ts +20 -0
- package/lib/browser/ai-configuration/ai-configuration-widget.d.ts.map +1 -0
- package/lib/browser/ai-configuration/ai-configuration-widget.js +88 -0
- package/lib/browser/ai-configuration/ai-configuration-widget.js.map +1 -0
- package/lib/browser/ai-configuration/language-model-renderer.d.ts +13 -0
- package/lib/browser/ai-configuration/language-model-renderer.d.ts.map +1 -0
- package/lib/browser/ai-configuration/language-model-renderer.js +104 -0
- package/lib/browser/ai-configuration/language-model-renderer.js.map +1 -0
- package/lib/browser/ai-configuration/template-settings-renderer.d.ts +11 -0
- package/lib/browser/ai-configuration/template-settings-renderer.d.ts.map +1 -0
- package/lib/browser/ai-configuration/template-settings-renderer.js +33 -0
- package/lib/browser/ai-configuration/template-settings-renderer.js.map +1 -0
- package/lib/browser/ai-configuration/variable-configuration-widget.d.ts +20 -0
- package/lib/browser/ai-configuration/variable-configuration-widget.d.ts.map +1 -0
- package/lib/browser/ai-configuration/variable-configuration-widget.js +99 -0
- package/lib/browser/ai-configuration/variable-configuration-widget.js.map +1 -0
- package/lib/browser/ai-core-frontend-application-contribution.d.ts +8 -0
- package/lib/browser/ai-core-frontend-application-contribution.d.ts.map +1 -0
- package/lib/browser/ai-core-frontend-application-contribution.js +46 -0
- package/lib/browser/ai-core-frontend-application-contribution.js.map +1 -0
- package/lib/browser/ai-core-frontend-module.d.ts +4 -0
- package/lib/browser/ai-core-frontend-module.d.ts.map +1 -0
- package/lib/browser/ai-core-frontend-module.js +122 -0
- package/lib/browser/ai-core-frontend-module.js.map +1 -0
- package/lib/browser/ai-core-preferences.d.ts +14 -0
- package/lib/browser/ai-core-preferences.d.ts.map +1 -0
- package/lib/browser/ai-core-preferences.js +69 -0
- package/lib/browser/ai-core-preferences.js.map +1 -0
- package/lib/browser/ai-settings-service.d.ts +14 -0
- package/lib/browser/ai-settings-service.d.ts.map +1 -0
- package/lib/browser/ai-settings-service.js +56 -0
- package/lib/browser/ai-settings-service.js.map +1 -0
- package/lib/browser/ai-view-contribution.d.ts +14 -0
- package/lib/browser/ai-view-contribution.d.ts.map +1 -0
- package/lib/browser/ai-view-contribution.js +71 -0
- package/lib/browser/ai-view-contribution.js.map +1 -0
- package/lib/browser/frontend-language-model-registry.d.ts +39 -0
- package/lib/browser/frontend-language-model-registry.d.ts.map +1 -0
- package/lib/browser/frontend-language-model-registry.js +321 -0
- package/lib/browser/frontend-language-model-registry.js.map +1 -0
- package/lib/browser/frontend-prompt-customization-service.d.ts +31 -0
- package/lib/browser/frontend-prompt-customization-service.d.ts.map +1 -0
- package/lib/browser/frontend-prompt-customization-service.js +194 -0
- package/lib/browser/frontend-prompt-customization-service.js.map +1 -0
- package/lib/browser/frontend-variable-service.d.ts +6 -0
- package/lib/browser/frontend-variable-service.d.ts.map +1 -0
- package/lib/browser/frontend-variable-service.js +31 -0
- package/lib/browser/frontend-variable-service.js.map +1 -0
- package/lib/browser/index.d.ts +11 -0
- package/lib/browser/index.d.ts.map +1 -0
- package/lib/browser/index.js +29 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/browser/prompttemplate-contribution.d.ts +28 -0
- package/lib/browser/prompttemplate-contribution.d.ts.map +1 -0
- package/lib/browser/prompttemplate-contribution.js +207 -0
- package/lib/browser/prompttemplate-contribution.js.map +1 -0
- package/lib/browser/theia-variable-contribution.d.ts +13 -0
- package/lib/browser/theia-variable-contribution.d.ts.map +1 -0
- package/lib/browser/theia-variable-contribution.js +64 -0
- package/lib/browser/theia-variable-contribution.js.map +1 -0
- package/lib/common/agent-service.d.ts +48 -0
- package/lib/common/agent-service.d.ts.map +1 -0
- package/lib/common/agent-service.js +88 -0
- package/lib/common/agent-service.js.map +1 -0
- package/lib/common/agent.d.ts +45 -0
- package/lib/common/agent.d.ts.map +1 -0
- package/lib/common/agent.js +20 -0
- package/lib/common/agent.js.map +1 -0
- package/lib/common/agents-variable-contribution.d.ts +19 -0
- package/lib/common/agents-variable-contribution.d.ts.map +1 -0
- package/lib/common/agents-variable-contribution.js +56 -0
- package/lib/common/agents-variable-contribution.js.map +1 -0
- package/lib/common/communication-recording-service.d.ts +23 -0
- package/lib/common/communication-recording-service.d.ts.map +1 -0
- package/lib/common/communication-recording-service.js +20 -0
- package/lib/common/communication-recording-service.js.map +1 -0
- package/lib/common/index.d.ts +16 -0
- package/lib/common/index.d.ts.map +1 -0
- package/lib/common/index.js +34 -0
- package/lib/common/index.js.map +1 -0
- package/lib/common/language-model-delegate.d.ts +24 -0
- package/lib/common/language-model-delegate.d.ts.map +1 -0
- package/lib/common/language-model-delegate.js +26 -0
- package/lib/common/language-model-delegate.js.map +1 -0
- package/lib/common/language-model-util.d.ts +5 -0
- package/lib/common/language-model-util.d.ts.map +1 -0
- package/lib/common/language-model-util.js +75 -0
- package/lib/common/language-model-util.js.map +1 -0
- package/lib/common/language-model.d.ts +137 -0
- package/lib/common/language-model.d.ts.map +1 -0
- package/lib/common/language-model.js +142 -0
- package/lib/common/language-model.js.map +1 -0
- package/lib/common/language-model.spec.d.ts +2 -0
- package/lib/common/language-model.spec.d.ts.map +1 -0
- package/lib/common/language-model.spec.js +62 -0
- package/lib/common/language-model.spec.js.map +1 -0
- package/lib/common/prompt-service-util.d.ts +5 -0
- package/lib/common/prompt-service-util.d.ts.map +1 -0
- package/lib/common/prompt-service-util.js +23 -0
- package/lib/common/prompt-service-util.js.map +1 -0
- package/lib/common/prompt-service.d.ts +101 -0
- package/lib/common/prompt-service.d.ts.map +1 -0
- package/lib/common/prompt-service.js +139 -0
- package/lib/common/prompt-service.js.map +1 -0
- package/lib/common/prompt-service.spec.d.ts +2 -0
- package/lib/common/prompt-service.spec.d.ts.map +1 -0
- package/lib/common/prompt-service.spec.js +86 -0
- package/lib/common/prompt-service.spec.js.map +1 -0
- package/lib/common/protocol.d.ts +7 -0
- package/lib/common/protocol.d.ts.map +1 -0
- package/lib/common/protocol.js +20 -0
- package/lib/common/protocol.js.map +1 -0
- package/lib/common/settings-service.d.ts +18 -0
- package/lib/common/settings-service.d.ts.map +1 -0
- package/lib/common/settings-service.js +5 -0
- package/lib/common/settings-service.js.map +1 -0
- package/lib/common/today-variable-contribution.d.ts +17 -0
- package/lib/common/today-variable-contribution.d.ts.map +1 -0
- package/lib/common/today-variable-contribution.js +48 -0
- package/lib/common/today-variable-contribution.js.map +1 -0
- package/lib/common/tomorrow-variable-contribution.d.ts +17 -0
- package/lib/common/tomorrow-variable-contribution.d.ts.map +1 -0
- package/lib/common/tomorrow-variable-contribution.js +48 -0
- package/lib/common/tomorrow-variable-contribution.js.map +1 -0
- package/lib/common/tool-invocation-registry.d.ts +23 -0
- package/lib/common/tool-invocation-registry.d.ts.map +1 -0
- package/lib/common/tool-invocation-registry.js +72 -0
- package/lib/common/tool-invocation-registry.js.map +1 -0
- package/lib/common/variable-service.d.ts +70 -0
- package/lib/common/variable-service.d.ts.map +1 -0
- package/lib/common/variable-service.js +122 -0
- package/lib/common/variable-service.js.map +1 -0
- package/lib/node/ai-core-backend-module.d.ts +4 -0
- package/lib/node/ai-core-backend-module.d.ts.map +1 -0
- package/lib/node/ai-core-backend-module.js +47 -0
- package/lib/node/ai-core-backend-module.js.map +1 -0
- package/lib/node/backend-language-model-registry.d.ts +12 -0
- package/lib/node/backend-language-model-registry.d.ts.map +1 -0
- package/lib/node/backend-language-model-registry.js +61 -0
- package/lib/node/backend-language-model-registry.js.map +1 -0
- package/lib/node/language-model-frontend-delegate.d.ts +18 -0
- package/lib/node/language-model-frontend-delegate.d.ts.map +1 -0
- package/lib/node/language-model-frontend-delegate.js +100 -0
- package/lib/node/language-model-frontend-delegate.js.map +1 -0
- package/package.json +59 -0
- package/src/browser/ai-activation-service.ts +56 -0
- package/src/browser/ai-command-handler-factory.ts +20 -0
- package/src/browser/ai-configuration/agent-configuration-widget.tsx +299 -0
- package/src/browser/ai-configuration/ai-configuration-service.ts +43 -0
- package/src/browser/ai-configuration/ai-configuration-view-contribution.ts +54 -0
- package/src/browser/ai-configuration/ai-configuration-widget.tsx +80 -0
- package/src/browser/ai-configuration/language-model-renderer.tsx +113 -0
- package/src/browser/ai-configuration/template-settings-renderer.tsx +39 -0
- package/src/browser/ai-configuration/variable-configuration-widget.tsx +110 -0
- package/src/browser/ai-core-frontend-application-contribution.ts +40 -0
- package/src/browser/ai-core-frontend-module.ts +161 -0
- package/src/browser/ai-core-preferences.ts +76 -0
- package/src/browser/ai-settings-service.ts +50 -0
- package/src/browser/ai-view-contribution.ts +77 -0
- package/src/browser/frontend-language-model-registry.ts +405 -0
- package/src/browser/frontend-prompt-customization-service.ts +197 -0
- package/src/browser/frontend-variable-service.ts +26 -0
- package/src/browser/index.ts +26 -0
- package/src/browser/prompttemplate-contribution.ts +250 -0
- package/src/browser/style/index.css +90 -0
- package/src/browser/theia-variable-contribution.ts +58 -0
- package/src/common/agent-service.ts +108 -0
- package/src/common/agent.ts +70 -0
- package/src/common/agents-variable-contribution.ts +64 -0
- package/src/common/communication-recording-service.ts +44 -0
- package/src/common/index.ts +30 -0
- package/src/common/language-model-delegate.ts +45 -0
- package/src/common/language-model-util.ts +67 -0
- package/src/common/language-model.spec.ts +86 -0
- package/src/common/language-model.ts +237 -0
- package/src/common/prompt-service-util.ts +21 -0
- package/src/common/prompt-service.spec.ts +98 -0
- package/src/common/prompt-service.ts +213 -0
- package/src/common/protocol.ts +23 -0
- package/src/common/settings-service.ts +33 -0
- package/src/common/today-variable-contribution.ts +67 -0
- package/src/common/tomorrow-variable-contribution.ts +66 -0
- package/src/common/tool-invocation-registry.ts +79 -0
- package/src/common/variable-service.ts +177 -0
- package/src/node/ai-core-backend-module.ts +83 -0
- package/src/node/backend-language-model-registry.ts +59 -0
- package/src/node/language-model-frontend-delegate.ts +116 -0
|
@@ -0,0 +1,50 @@
|
|
|
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
|
+
import { DisposableCollection, Emitter, Event } from '@theia/core';
|
|
17
|
+
import { PreferenceScope, PreferenceService } from '@theia/core/lib/browser';
|
|
18
|
+
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
19
|
+
import { JSONObject } from '@theia/core/shared/@phosphor/coreutils';
|
|
20
|
+
import { AISettings, AISettingsService, AgentSettings } from '../common';
|
|
21
|
+
|
|
22
|
+
@injectable()
|
|
23
|
+
export class AISettingsServiceImpl implements AISettingsService {
|
|
24
|
+
@inject(PreferenceService) protected preferenceService: PreferenceService;
|
|
25
|
+
static readonly PREFERENCE_NAME = 'ai-features.agentSettings';
|
|
26
|
+
|
|
27
|
+
protected toDispose = new DisposableCollection();
|
|
28
|
+
|
|
29
|
+
protected readonly onDidChangeEmitter = new Emitter<void>();
|
|
30
|
+
onDidChange: Event<void> = this.onDidChangeEmitter.event;
|
|
31
|
+
|
|
32
|
+
async updateAgentSettings(agent: string, agentSettings: Partial<AgentSettings>): Promise<void> {
|
|
33
|
+
const settings = await this.getSettings();
|
|
34
|
+
const newAgentSettings = { ...settings[agent], ...agentSettings };
|
|
35
|
+
settings[agent] = newAgentSettings;
|
|
36
|
+
this.preferenceService.set(AISettingsServiceImpl.PREFERENCE_NAME, settings, PreferenceScope.User);
|
|
37
|
+
this.onDidChangeEmitter.fire();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async getAgentSettings(agent: string): Promise<AgentSettings | undefined> {
|
|
41
|
+
const settings = await this.getSettings();
|
|
42
|
+
return settings[agent];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async getSettings(): Promise<AISettings> {
|
|
46
|
+
await this.preferenceService.ready;
|
|
47
|
+
const pref = this.preferenceService.inspect<AISettings & JSONObject>(AISettingsServiceImpl.PREFERENCE_NAME);
|
|
48
|
+
return pref?.value ? pref.value : {};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
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
|
+
import { CommandRegistry, MenuModelRegistry } from '@theia/core';
|
|
17
|
+
import { AbstractViewContribution, CommonMenus, KeybindingRegistry, PreferenceService, Widget } from '@theia/core/lib/browser';
|
|
18
|
+
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
|
|
19
|
+
import { AIActivationService, EXPERIMENTAL_AI_CONTEXT_KEY } from './ai-activation-service';
|
|
20
|
+
import { AICommandHandlerFactory } from './ai-command-handler-factory';
|
|
21
|
+
|
|
22
|
+
@injectable()
|
|
23
|
+
export class AIViewContribution<T extends Widget> extends AbstractViewContribution<T> {
|
|
24
|
+
|
|
25
|
+
@inject(PreferenceService)
|
|
26
|
+
protected readonly preferenceService: PreferenceService;
|
|
27
|
+
|
|
28
|
+
@inject(AIActivationService)
|
|
29
|
+
protected readonly activationService: AIActivationService;
|
|
30
|
+
|
|
31
|
+
@inject(AICommandHandlerFactory)
|
|
32
|
+
protected readonly commandHandlerFactory: AICommandHandlerFactory;
|
|
33
|
+
|
|
34
|
+
@postConstruct()
|
|
35
|
+
protected init(): void {
|
|
36
|
+
this.activationService.onDidChangeActiveStatus(active => {
|
|
37
|
+
if (!active) {
|
|
38
|
+
this.closeView();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override registerCommands(commands: CommandRegistry): void {
|
|
44
|
+
if (this.toggleCommand) {
|
|
45
|
+
|
|
46
|
+
commands.registerCommand(this.toggleCommand, this.commandHandlerFactory({
|
|
47
|
+
execute: () => this.toggleView(),
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
this.quickView?.registerItem({
|
|
51
|
+
label: this.viewLabel,
|
|
52
|
+
when: EXPERIMENTAL_AI_CONTEXT_KEY,
|
|
53
|
+
open: () => this.openView({ activate: true })
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
override registerMenus(menus: MenuModelRegistry): void {
|
|
59
|
+
if (this.toggleCommand) {
|
|
60
|
+
menus.registerMenuAction(CommonMenus.VIEW_VIEWS, {
|
|
61
|
+
commandId: this.toggleCommand.id,
|
|
62
|
+
when: EXPERIMENTAL_AI_CONTEXT_KEY,
|
|
63
|
+
label: this.viewLabel
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
override registerKeybindings(keybindings: KeybindingRegistry): void {
|
|
68
|
+
if (this.toggleCommand && this.options.toggleKeybinding) {
|
|
69
|
+
keybindings.registerKeybinding({
|
|
70
|
+
command: this.toggleCommand.id,
|
|
71
|
+
when: EXPERIMENTAL_AI_CONTEXT_KEY,
|
|
72
|
+
keybinding: this.options.toggleKeybinding
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
@@ -0,0 +1,405 @@
|
|
|
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
|
+
import { CancellationToken, ILogger } from '@theia/core';
|
|
17
|
+
import {
|
|
18
|
+
inject,
|
|
19
|
+
injectable,
|
|
20
|
+
postConstruct,
|
|
21
|
+
} from '@theia/core/shared/inversify';
|
|
22
|
+
import {
|
|
23
|
+
OutputChannel,
|
|
24
|
+
OutputChannelManager,
|
|
25
|
+
OutputChannelSeverity,
|
|
26
|
+
} from '@theia/output/lib/browser/output-channel';
|
|
27
|
+
import {
|
|
28
|
+
AISettingsService,
|
|
29
|
+
DefaultLanguageModelRegistryImpl,
|
|
30
|
+
isLanguageModelParsedResponse,
|
|
31
|
+
isLanguageModelStreamResponse,
|
|
32
|
+
isLanguageModelStreamResponseDelegate,
|
|
33
|
+
isLanguageModelTextResponse,
|
|
34
|
+
isModelMatching,
|
|
35
|
+
LanguageModel,
|
|
36
|
+
LanguageModelDelegateClient,
|
|
37
|
+
LanguageModelFrontendDelegate,
|
|
38
|
+
LanguageModelMetaData,
|
|
39
|
+
LanguageModelRegistryClient,
|
|
40
|
+
LanguageModelRegistryFrontendDelegate,
|
|
41
|
+
LanguageModelRequest,
|
|
42
|
+
LanguageModelResponse,
|
|
43
|
+
LanguageModelSelector,
|
|
44
|
+
LanguageModelStreamResponsePart,
|
|
45
|
+
} from '../common';
|
|
46
|
+
|
|
47
|
+
@injectable()
|
|
48
|
+
export class LanguageModelDelegateClientImpl
|
|
49
|
+
implements LanguageModelDelegateClient, LanguageModelRegistryClient {
|
|
50
|
+
protected receiver: FrontendLanguageModelRegistryImpl;
|
|
51
|
+
|
|
52
|
+
setReceiver(receiver: FrontendLanguageModelRegistryImpl): void {
|
|
53
|
+
this.receiver = receiver;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
send(id: string, token: LanguageModelStreamResponsePart | undefined): void {
|
|
57
|
+
this.receiver.send(id, token);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
toolCall(requestId: string, toolId: string, args_string: string): Promise<unknown> {
|
|
61
|
+
return this.receiver.toolCall(requestId, toolId, args_string);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
languageModelAdded(metadata: LanguageModelMetaData): void {
|
|
65
|
+
this.receiver.languageModelAdded(metadata);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
languageModelRemoved(id: string): void {
|
|
69
|
+
this.receiver.languageModelRemoved(id);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface StreamState {
|
|
74
|
+
id: string;
|
|
75
|
+
tokens: (LanguageModelStreamResponsePart | undefined)[];
|
|
76
|
+
resolve?: (_: unknown) => void;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@injectable()
|
|
80
|
+
export class FrontendLanguageModelRegistryImpl
|
|
81
|
+
extends DefaultLanguageModelRegistryImpl {
|
|
82
|
+
|
|
83
|
+
// called by backend
|
|
84
|
+
languageModelAdded(metadata: LanguageModelMetaData): void {
|
|
85
|
+
this.addLanguageModels([metadata]);
|
|
86
|
+
}
|
|
87
|
+
// called by backend
|
|
88
|
+
languageModelRemoved(id: string): void {
|
|
89
|
+
this.removeLanguageModels([id]);
|
|
90
|
+
}
|
|
91
|
+
@inject(LanguageModelRegistryFrontendDelegate)
|
|
92
|
+
protected registryDelegate: LanguageModelRegistryFrontendDelegate;
|
|
93
|
+
|
|
94
|
+
@inject(LanguageModelFrontendDelegate)
|
|
95
|
+
protected providerDelegate: LanguageModelFrontendDelegate;
|
|
96
|
+
|
|
97
|
+
@inject(LanguageModelDelegateClientImpl)
|
|
98
|
+
protected client: LanguageModelDelegateClientImpl;
|
|
99
|
+
|
|
100
|
+
@inject(ILogger)
|
|
101
|
+
protected override logger: ILogger;
|
|
102
|
+
|
|
103
|
+
@inject(OutputChannelManager)
|
|
104
|
+
protected outputChannelManager: OutputChannelManager;
|
|
105
|
+
|
|
106
|
+
@inject(AISettingsService)
|
|
107
|
+
protected settingsService: AISettingsService;
|
|
108
|
+
|
|
109
|
+
private static requestCounter: number = 0;
|
|
110
|
+
|
|
111
|
+
override addLanguageModels(models: LanguageModelMetaData[] | LanguageModel[]): void {
|
|
112
|
+
let modelAdded = false;
|
|
113
|
+
for (const model of models) {
|
|
114
|
+
if (this.languageModels.find(m => m.id === model.id)) {
|
|
115
|
+
console.warn(`Tried to add an existing model ${model.id}`);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (LanguageModel.is(model)) {
|
|
119
|
+
this.languageModels.push(
|
|
120
|
+
new Proxy(
|
|
121
|
+
model,
|
|
122
|
+
languageModelOutputHandler(
|
|
123
|
+
() => this.outputChannelManager.getChannel(
|
|
124
|
+
model.id
|
|
125
|
+
)
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
);
|
|
129
|
+
modelAdded = true;
|
|
130
|
+
} else {
|
|
131
|
+
this.languageModels.push(
|
|
132
|
+
new Proxy(
|
|
133
|
+
this.createFrontendLanguageModel(
|
|
134
|
+
model
|
|
135
|
+
),
|
|
136
|
+
languageModelOutputHandler(
|
|
137
|
+
() => this.outputChannelManager.getChannel(
|
|
138
|
+
model.id
|
|
139
|
+
)
|
|
140
|
+
)
|
|
141
|
+
)
|
|
142
|
+
);
|
|
143
|
+
modelAdded = true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (modelAdded) {
|
|
147
|
+
this.changeEmitter.fire({ models: this.languageModels });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@postConstruct()
|
|
152
|
+
protected override init(): void {
|
|
153
|
+
this.client.setReceiver(this);
|
|
154
|
+
|
|
155
|
+
const contributions =
|
|
156
|
+
this.languageModelContributions.getContributions();
|
|
157
|
+
const promises = contributions.map(provider => provider());
|
|
158
|
+
const backendDescriptions =
|
|
159
|
+
this.registryDelegate.getLanguageModelDescriptions();
|
|
160
|
+
|
|
161
|
+
Promise.allSettled([backendDescriptions, ...promises]).then(
|
|
162
|
+
results => {
|
|
163
|
+
const backendDescriptionsResult = results[0];
|
|
164
|
+
if (backendDescriptionsResult.status === 'fulfilled') {
|
|
165
|
+
this.addLanguageModels(backendDescriptionsResult.value);
|
|
166
|
+
} else {
|
|
167
|
+
this.logger.error(
|
|
168
|
+
'Failed to add language models contributed from the backend',
|
|
169
|
+
backendDescriptionsResult.reason
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
for (let i = 1; i < results.length; i++) {
|
|
173
|
+
// assert that index > 0 contains only language models
|
|
174
|
+
const languageModelResult = results[i] as
|
|
175
|
+
| PromiseRejectedResult
|
|
176
|
+
| PromiseFulfilledResult<LanguageModel[]>;
|
|
177
|
+
if (languageModelResult.status === 'fulfilled') {
|
|
178
|
+
this.addLanguageModels(languageModelResult.value);
|
|
179
|
+
} else {
|
|
180
|
+
this.logger.error(
|
|
181
|
+
'Failed to add some language models:',
|
|
182
|
+
languageModelResult.reason
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
this.markInitialized();
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
createFrontendLanguageModel(
|
|
192
|
+
description: LanguageModelMetaData
|
|
193
|
+
): LanguageModel {
|
|
194
|
+
return {
|
|
195
|
+
...description,
|
|
196
|
+
request: async (request: LanguageModelRequest, cancellationToken?: CancellationToken) => {
|
|
197
|
+
const requestId = `${FrontendLanguageModelRegistryImpl.requestCounter++}`;
|
|
198
|
+
this.requests.set(requestId, request);
|
|
199
|
+
cancellationToken?.onCancellationRequested(() => {
|
|
200
|
+
this.providerDelegate.cancel(requestId);
|
|
201
|
+
});
|
|
202
|
+
const response = await this.providerDelegate.request(
|
|
203
|
+
description.id,
|
|
204
|
+
request,
|
|
205
|
+
requestId,
|
|
206
|
+
cancellationToken
|
|
207
|
+
);
|
|
208
|
+
if (isLanguageModelTextResponse(response) || isLanguageModelParsedResponse(response)) {
|
|
209
|
+
return response;
|
|
210
|
+
}
|
|
211
|
+
if (isLanguageModelStreamResponseDelegate(response)) {
|
|
212
|
+
if (!this.streams.has(response.streamId)) {
|
|
213
|
+
const newStreamState = {
|
|
214
|
+
id: response.streamId,
|
|
215
|
+
tokens: [],
|
|
216
|
+
};
|
|
217
|
+
this.streams.set(response.streamId, newStreamState);
|
|
218
|
+
}
|
|
219
|
+
const streamState = this.streams.get(response.streamId)!;
|
|
220
|
+
return {
|
|
221
|
+
stream: this.getIterable(streamState),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
this.logger.error(
|
|
225
|
+
`Received unknown response in frontend for request to language model ${description.id}. Trying to continue without touching the response.`,
|
|
226
|
+
response
|
|
227
|
+
);
|
|
228
|
+
return response;
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private streams = new Map<string, StreamState>();
|
|
234
|
+
private requests = new Map<string, LanguageModelRequest>();
|
|
235
|
+
|
|
236
|
+
async *getIterable(
|
|
237
|
+
state: StreamState
|
|
238
|
+
): AsyncIterable<LanguageModelStreamResponsePart> {
|
|
239
|
+
let current = -1;
|
|
240
|
+
while (true) {
|
|
241
|
+
if (current < state.tokens.length - 1) {
|
|
242
|
+
current++;
|
|
243
|
+
const token = state.tokens[current];
|
|
244
|
+
if (token === undefined) {
|
|
245
|
+
// message is finished
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
if (token !== undefined) {
|
|
249
|
+
yield token;
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
await new Promise(resolve => {
|
|
253
|
+
state.resolve = resolve;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
this.streams.delete(state.id);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// called by backend via the "delegate client" with new tokens
|
|
261
|
+
send(id: string, token: LanguageModelStreamResponsePart | undefined): void {
|
|
262
|
+
if (!this.streams.has(id)) {
|
|
263
|
+
const newStreamState = {
|
|
264
|
+
id,
|
|
265
|
+
tokens: [],
|
|
266
|
+
};
|
|
267
|
+
this.streams.set(id, newStreamState);
|
|
268
|
+
}
|
|
269
|
+
const streamState = this.streams.get(id)!;
|
|
270
|
+
streamState.tokens.push(token);
|
|
271
|
+
if (streamState.resolve) {
|
|
272
|
+
streamState.resolve(token);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// called by backend once tool is invoked
|
|
277
|
+
toolCall(id: string, toolId: string, arg_string: string): Promise<unknown> {
|
|
278
|
+
if (!this.requests.has(id)) {
|
|
279
|
+
throw new Error('Somehow we got a callback for a non existing request!');
|
|
280
|
+
}
|
|
281
|
+
const request = this.requests.get(id)!;
|
|
282
|
+
const tool = request.tools?.find(t => t.id === toolId);
|
|
283
|
+
if (tool) {
|
|
284
|
+
return tool.handler(arg_string);
|
|
285
|
+
}
|
|
286
|
+
throw new Error(`Could not find a tool for ${toolId}!`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
override async selectLanguageModels(request: LanguageModelSelector): Promise<LanguageModel[]> {
|
|
290
|
+
await this.initialized;
|
|
291
|
+
const userSettings = (await this.settingsService.getAgentSettings(request.agent))?.languageModelRequirements?.find(req => req.purpose === request.purpose);
|
|
292
|
+
if (userSettings?.identifier) {
|
|
293
|
+
const model = await this.getLanguageModel(userSettings.identifier);
|
|
294
|
+
if (model) {
|
|
295
|
+
return [model];
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return this.languageModels.filter(model => isModelMatching(request, model));
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
override async selectLanguageModel(request: LanguageModelSelector): Promise<LanguageModel | undefined> {
|
|
302
|
+
return (await this.selectLanguageModels(request))[0];
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const formatJsonWithIndentation = (obj: unknown): string[] => {
|
|
307
|
+
// eslint-disable-next-line no-null/no-null
|
|
308
|
+
const jsonString = JSON.stringify(obj, null, 2);
|
|
309
|
+
const lines = jsonString.split('\n');
|
|
310
|
+
const formattedLines: string[] = [];
|
|
311
|
+
|
|
312
|
+
lines.forEach(line => {
|
|
313
|
+
const subLines = line.split('\\n');
|
|
314
|
+
const index = indexOfValue(subLines[0]) + 1;
|
|
315
|
+
formattedLines.push(subLines[0]);
|
|
316
|
+
const prefix = index > 0 ? ' '.repeat(index) : '';
|
|
317
|
+
if (index !== -1) {
|
|
318
|
+
for (let i = 1; i < subLines.length; i++) {
|
|
319
|
+
formattedLines.push(prefix + subLines[i]);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
return formattedLines;
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const indexOfValue = (jsonLine: string): number => {
|
|
328
|
+
const pattern = /"([^"]+)"\s*:\s*/g;
|
|
329
|
+
const match = pattern.exec(jsonLine);
|
|
330
|
+
return match ? match.index + match[0].length : -1;
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
const languageModelOutputHandler = (
|
|
334
|
+
outputChannelGetter: () => OutputChannel
|
|
335
|
+
): ProxyHandler<LanguageModel> => ({
|
|
336
|
+
get<K extends keyof LanguageModel>(
|
|
337
|
+
target: LanguageModel,
|
|
338
|
+
prop: K,
|
|
339
|
+
): LanguageModel[K] | LanguageModel['request'] {
|
|
340
|
+
const original = target[prop];
|
|
341
|
+
if (prop === 'request' && typeof original === 'function') {
|
|
342
|
+
return async function (
|
|
343
|
+
...args: Parameters<LanguageModel['request']>
|
|
344
|
+
): Promise<LanguageModelResponse> {
|
|
345
|
+
const outputChannel = outputChannelGetter();
|
|
346
|
+
outputChannel.appendLine(
|
|
347
|
+
'Sending request:'
|
|
348
|
+
);
|
|
349
|
+
const formattedRequest = formatJsonWithIndentation(args[0]);
|
|
350
|
+
formattedRequest.forEach(line => outputChannel.appendLine(line));
|
|
351
|
+
if (args[1]) {
|
|
352
|
+
args[1] = new Proxy(args[1], {
|
|
353
|
+
get<CK extends keyof CancellationToken>(
|
|
354
|
+
cTarget: CancellationToken,
|
|
355
|
+
cProp: CK
|
|
356
|
+
): CancellationToken[CK] | CancellationToken['onCancellationRequested'] {
|
|
357
|
+
if (cProp === 'onCancellationRequested') {
|
|
358
|
+
return (...cargs: Parameters<CancellationToken['onCancellationRequested']>) => cTarget.onCancellationRequested(() => {
|
|
359
|
+
outputChannel.appendLine('\nCancel requested', OutputChannelSeverity.Warning);
|
|
360
|
+
cargs[0]();
|
|
361
|
+
}, cargs[1], cargs[2]);
|
|
362
|
+
}
|
|
363
|
+
return cTarget[cProp];
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
const result = await original.apply(target, args);
|
|
369
|
+
if (isLanguageModelStreamResponse(result)) {
|
|
370
|
+
outputChannel.appendLine('Received a response stream');
|
|
371
|
+
const stream = result.stream;
|
|
372
|
+
const loggedStream = {
|
|
373
|
+
async *[Symbol.asyncIterator](): AsyncIterator<LanguageModelStreamResponsePart> {
|
|
374
|
+
for await (const part of stream) {
|
|
375
|
+
outputChannel.append(part.content || '');
|
|
376
|
+
yield part;
|
|
377
|
+
}
|
|
378
|
+
outputChannel.append('\n');
|
|
379
|
+
outputChannel.appendLine('End of stream');
|
|
380
|
+
},
|
|
381
|
+
};
|
|
382
|
+
return {
|
|
383
|
+
...result,
|
|
384
|
+
stream: loggedStream,
|
|
385
|
+
};
|
|
386
|
+
} else {
|
|
387
|
+
outputChannel.appendLine('Received a response');
|
|
388
|
+
outputChannel.appendLine(JSON.stringify(result));
|
|
389
|
+
return result;
|
|
390
|
+
}
|
|
391
|
+
} catch (err) {
|
|
392
|
+
outputChannel.appendLine('An error occurred');
|
|
393
|
+
if (err instanceof Error) {
|
|
394
|
+
outputChannel.appendLine(
|
|
395
|
+
err.message,
|
|
396
|
+
OutputChannelSeverity.Error
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
throw err;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
return original;
|
|
404
|
+
},
|
|
405
|
+
});
|