@theia/ai-chat 1.55.1 → 1.57.0-next.22
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/lib/common/chat-agents.d.ts +12 -4
- package/lib/common/chat-agents.d.ts.map +1 -1
- package/lib/common/chat-agents.js +37 -46
- package/lib/common/chat-agents.js.map +1 -1
- package/lib/common/chat-history-entry.d.ts +7 -0
- package/lib/common/chat-history-entry.d.ts.map +1 -0
- package/lib/common/chat-history-entry.js +42 -0
- package/lib/common/chat-history-entry.js.map +1 -0
- package/lib/common/chat-model-util.d.ts +7 -0
- package/lib/common/chat-model-util.d.ts.map +1 -0
- package/lib/common/chat-model-util.js +50 -0
- package/lib/common/chat-model-util.js.map +1 -0
- package/lib/common/chat-model.d.ts +59 -0
- package/lib/common/chat-model.d.ts.map +1 -1
- package/lib/common/chat-model.js +70 -2
- package/lib/common/chat-model.js.map +1 -1
- package/lib/common/command-chat-agents.d.ts.map +1 -1
- package/lib/common/command-chat-agents.js +3 -1
- package/lib/common/command-chat-agents.js.map +1 -1
- package/lib/common/index.d.ts +1 -0
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +1 -0
- package/lib/common/index.js.map +1 -1
- package/lib/common/orchestrator-chat-agent.d.ts.map +1 -1
- package/lib/common/orchestrator-chat-agent.js +16 -14
- package/lib/common/orchestrator-chat-agent.js.map +1 -1
- package/lib/common/parse-contents.d.ts +2 -2
- package/lib/common/parse-contents.d.ts.map +1 -1
- package/lib/common/parse-contents.js +4 -4
- package/lib/common/parse-contents.js.map +1 -1
- package/lib/common/parse-contents.spec.d.ts.map +1 -1
- package/lib/common/parse-contents.spec.js +14 -13
- package/lib/common/parse-contents.spec.js.map +1 -1
- package/lib/common/response-content-matcher.d.ts +3 -3
- package/lib/common/response-content-matcher.d.ts.map +1 -1
- package/lib/common/response-content-matcher.js +2 -2
- package/lib/common/response-content-matcher.js.map +1 -1
- package/lib/common/universal-chat-agent.d.ts +1 -0
- package/lib/common/universal-chat-agent.d.ts.map +1 -1
- package/lib/common/universal-chat-agent.js +10 -3
- package/lib/common/universal-chat-agent.js.map +1 -1
- package/package.json +8 -8
- package/src/common/chat-agents.ts +44 -54
- package/src/common/chat-history-entry.ts +47 -0
- package/src/common/chat-model-util.ts +44 -0
- package/src/common/chat-model.ts +89 -0
- package/src/common/command-chat-agents.ts +3 -1
- package/src/common/index.ts +1 -0
- package/src/common/orchestrator-chat-agent.ts +17 -14
- package/src/common/parse-contents.spec.ts +16 -14
- package/src/common/parse-contents.ts +5 -4
- package/src/common/response-content-matcher.ts +4 -3
- package/src/common/universal-chat-agent.ts +10 -2
|
@@ -23,10 +23,13 @@ import { ChatAgentService } from './chat-agent-service';
|
|
|
23
23
|
import { AbstractStreamParsingChatAgent, ChatAgent, SystemMessageDescription } from './chat-agents';
|
|
24
24
|
import { ChatRequestModelImpl, InformationalChatResponseContentImpl } from './chat-model';
|
|
25
25
|
import { generateUuid } from '@theia/core';
|
|
26
|
+
import { ChatHistoryEntry } from './chat-history-entry';
|
|
26
27
|
|
|
27
28
|
export const orchestratorTemplate: PromptTemplate = {
|
|
28
29
|
id: 'orchestrator-system',
|
|
29
|
-
template:
|
|
30
|
+
template: `{{!-- Made improvements or adaptations to this prompt template? We’d love for you to share it with the community! Contribute back here:
|
|
31
|
+
https://github.com/eclipse-theia/theia/discussions/new?category=prompt-template-contribution --}}
|
|
32
|
+
# Instructions
|
|
30
33
|
|
|
31
34
|
Your task is to identify which Chat Agent(s) should best reply a given user's message.
|
|
32
35
|
You consider all messages of the conversation to ensure consistency and avoid agent switches without a clear context change.
|
|
@@ -60,7 +63,7 @@ You must only use the \`id\` attribute of the agent, never the name.
|
|
|
60
63
|
`};
|
|
61
64
|
|
|
62
65
|
export const OrchestratorChatAgentId = 'Orchestrator';
|
|
63
|
-
const
|
|
66
|
+
const OrchestratorRequestIdKey = 'orchestatorRequestIdKey';
|
|
64
67
|
|
|
65
68
|
@injectable()
|
|
66
69
|
export class OrchestratorChatAgent extends AbstractStreamParsingChatAgent implements ChatAgent {
|
|
@@ -93,16 +96,17 @@ export class OrchestratorChatAgent extends AbstractStreamParsingChatAgent implem
|
|
|
93
96
|
override async invoke(request: ChatRequestModelImpl): Promise<void> {
|
|
94
97
|
request.response.addProgressMessage({ content: 'Determining the most appropriate agent', status: 'inProgress' });
|
|
95
98
|
// We generate a dedicated ID for recording the orchestrator request/response, as we will forward the original request to another agent
|
|
96
|
-
const
|
|
97
|
-
request.addData(
|
|
98
|
-
const
|
|
99
|
-
this.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
99
|
+
const orchestratorRequestId = generateUuid();
|
|
100
|
+
request.addData(OrchestratorRequestIdKey, orchestratorRequestId);
|
|
101
|
+
const messages = await this.getMessages(request.session);
|
|
102
|
+
const systemMessage = (await this.getSystemMessageDescription())?.text;
|
|
103
|
+
this.recordingService.recordRequest(
|
|
104
|
+
ChatHistoryEntry.fromRequest(this.id, request, {
|
|
105
|
+
requestId: orchestratorRequestId,
|
|
106
|
+
messages,
|
|
107
|
+
systemMessage
|
|
108
|
+
})
|
|
109
|
+
);
|
|
106
110
|
return super.invoke(request);
|
|
107
111
|
}
|
|
108
112
|
|
|
@@ -115,12 +119,11 @@ export class OrchestratorChatAgent extends AbstractStreamParsingChatAgent implem
|
|
|
115
119
|
let agentIds: string[] = [];
|
|
116
120
|
const responseText = await getTextOfResponse(response);
|
|
117
121
|
// We use the previously generated, dedicated ID to log the orchestrator response before we forward the original request
|
|
118
|
-
const orchestratorRequestId = request.getDataByKey(
|
|
122
|
+
const orchestratorRequestId = request.getDataByKey(OrchestratorRequestIdKey);
|
|
119
123
|
if (typeof orchestratorRequestId === 'string') {
|
|
120
124
|
this.recordingService.recordResponse({
|
|
121
125
|
agentId: this.id,
|
|
122
126
|
sessionId: request.session.id,
|
|
123
|
-
timestamp: Date.now(),
|
|
124
127
|
requestId: orchestratorRequestId,
|
|
125
128
|
response: responseText,
|
|
126
129
|
});
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import { expect } from 'chai';
|
|
18
|
-
import { ChatResponseContent, CodeChatResponseContentImpl, MarkdownChatResponseContentImpl } from './chat-model';
|
|
18
|
+
import { ChatRequestModelImpl, ChatResponseContent, CodeChatResponseContentImpl, MarkdownChatResponseContentImpl } from './chat-model';
|
|
19
19
|
import { parseContents } from './parse-contents';
|
|
20
20
|
import { CodeContentMatcher, ResponseContentMatcher } from './response-content-matcher';
|
|
21
21
|
|
|
@@ -33,22 +33,24 @@ export const CommandContentMatcher: ResponseContentMatcher = {
|
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
const fakeRequest = {} as ChatRequestModelImpl;
|
|
37
|
+
|
|
36
38
|
describe('parseContents', () => {
|
|
37
39
|
it('should parse code content', () => {
|
|
38
40
|
const text = '```typescript\nconsole.log("Hello World");\n```';
|
|
39
|
-
const result = parseContents(text);
|
|
41
|
+
const result = parseContents(text, fakeRequest);
|
|
40
42
|
expect(result).to.deep.equal([new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript')]);
|
|
41
43
|
});
|
|
42
44
|
|
|
43
45
|
it('should parse markdown content', () => {
|
|
44
46
|
const text = 'Hello **World**';
|
|
45
|
-
const result = parseContents(text);
|
|
47
|
+
const result = parseContents(text, fakeRequest);
|
|
46
48
|
expect(result).to.deep.equal([new MarkdownChatResponseContentImpl('Hello **World**')]);
|
|
47
49
|
});
|
|
48
50
|
|
|
49
51
|
it('should parse multiple content blocks', () => {
|
|
50
52
|
const text = '```typescript\nconsole.log("Hello World");\n```\nHello **World**';
|
|
51
|
-
const result = parseContents(text);
|
|
53
|
+
const result = parseContents(text, fakeRequest);
|
|
52
54
|
expect(result).to.deep.equal([
|
|
53
55
|
new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
|
|
54
56
|
new MarkdownChatResponseContentImpl('\nHello **World**')
|
|
@@ -57,7 +59,7 @@ describe('parseContents', () => {
|
|
|
57
59
|
|
|
58
60
|
it('should parse multiple content blocks with different languages', () => {
|
|
59
61
|
const text = '```typescript\nconsole.log("Hello World");\n```\n```python\nprint("Hello World")\n```';
|
|
60
|
-
const result = parseContents(text);
|
|
62
|
+
const result = parseContents(text, fakeRequest);
|
|
61
63
|
expect(result).to.deep.equal([
|
|
62
64
|
new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
|
|
63
65
|
new CodeChatResponseContentImpl('print("Hello World")', 'python')
|
|
@@ -66,7 +68,7 @@ describe('parseContents', () => {
|
|
|
66
68
|
|
|
67
69
|
it('should parse multiple content blocks with different languages and markdown', () => {
|
|
68
70
|
const text = '```typescript\nconsole.log("Hello World");\n```\nHello **World**\n```python\nprint("Hello World")\n```';
|
|
69
|
-
const result = parseContents(text);
|
|
71
|
+
const result = parseContents(text, fakeRequest);
|
|
70
72
|
expect(result).to.deep.equal([
|
|
71
73
|
new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
|
|
72
74
|
new MarkdownChatResponseContentImpl('\nHello **World**\n'),
|
|
@@ -76,7 +78,7 @@ describe('parseContents', () => {
|
|
|
76
78
|
|
|
77
79
|
it('should parse content blocks with empty content', () => {
|
|
78
80
|
const text = '```typescript\n```\nHello **World**\n```python\nprint("Hello World")\n```';
|
|
79
|
-
const result = parseContents(text);
|
|
81
|
+
const result = parseContents(text, fakeRequest);
|
|
80
82
|
expect(result).to.deep.equal([
|
|
81
83
|
new CodeChatResponseContentImpl('', 'typescript'),
|
|
82
84
|
new MarkdownChatResponseContentImpl('\nHello **World**\n'),
|
|
@@ -86,7 +88,7 @@ describe('parseContents', () => {
|
|
|
86
88
|
|
|
87
89
|
it('should parse content with markdown, code, and markdown', () => {
|
|
88
90
|
const text = 'Hello **World**\n```typescript\nconsole.log("Hello World");\n```\nGoodbye **World**';
|
|
89
|
-
const result = parseContents(text);
|
|
91
|
+
const result = parseContents(text, fakeRequest);
|
|
90
92
|
expect(result).to.deep.equal([
|
|
91
93
|
new MarkdownChatResponseContentImpl('Hello **World**\n'),
|
|
92
94
|
new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
|
|
@@ -96,25 +98,25 @@ describe('parseContents', () => {
|
|
|
96
98
|
|
|
97
99
|
it('should handle text with no special content', () => {
|
|
98
100
|
const text = 'Just some plain text.';
|
|
99
|
-
const result = parseContents(text);
|
|
101
|
+
const result = parseContents(text, fakeRequest);
|
|
100
102
|
expect(result).to.deep.equal([new MarkdownChatResponseContentImpl('Just some plain text.')]);
|
|
101
103
|
});
|
|
102
104
|
|
|
103
105
|
it('should handle text with only start code block', () => {
|
|
104
106
|
const text = '```typescript\nconsole.log("Hello World");';
|
|
105
|
-
const result = parseContents(text);
|
|
107
|
+
const result = parseContents(text, fakeRequest);
|
|
106
108
|
expect(result).to.deep.equal([new MarkdownChatResponseContentImpl('```typescript\nconsole.log("Hello World");')]);
|
|
107
109
|
});
|
|
108
110
|
|
|
109
111
|
it('should handle text with only end code block', () => {
|
|
110
112
|
const text = 'console.log("Hello World");\n```';
|
|
111
|
-
const result = parseContents(text);
|
|
113
|
+
const result = parseContents(text, fakeRequest);
|
|
112
114
|
expect(result).to.deep.equal([new MarkdownChatResponseContentImpl('console.log("Hello World");\n```')]);
|
|
113
115
|
});
|
|
114
116
|
|
|
115
117
|
it('should handle text with unmatched code block', () => {
|
|
116
118
|
const text = '```typescript\nconsole.log("Hello World");\n```\n```python\nprint("Hello World")';
|
|
117
|
-
const result = parseContents(text);
|
|
119
|
+
const result = parseContents(text, fakeRequest);
|
|
118
120
|
expect(result).to.deep.equal([
|
|
119
121
|
new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
|
|
120
122
|
new MarkdownChatResponseContentImpl('\n```python\nprint("Hello World")')
|
|
@@ -123,7 +125,7 @@ describe('parseContents', () => {
|
|
|
123
125
|
|
|
124
126
|
it('should parse code block without newline after language', () => {
|
|
125
127
|
const text = '```typescript console.log("Hello World");```';
|
|
126
|
-
const result = parseContents(text);
|
|
128
|
+
const result = parseContents(text, fakeRequest);
|
|
127
129
|
expect(result).to.deep.equal([
|
|
128
130
|
new MarkdownChatResponseContentImpl('```typescript console.log("Hello World");```')
|
|
129
131
|
]);
|
|
@@ -131,7 +133,7 @@ describe('parseContents', () => {
|
|
|
131
133
|
|
|
132
134
|
it('should parse with matches of multiple different matchers and default', () => {
|
|
133
135
|
const text = '<command>\nMY_SPECIAL_COMMAND\n</command>\nHello **World**\n```python\nprint("Hello World")\n```\n<command>\nMY_SPECIAL_COMMAND2\n</command>';
|
|
134
|
-
const result = parseContents(text, [CodeContentMatcher, CommandContentMatcher]);
|
|
136
|
+
const result = parseContents(text, fakeRequest, [CodeContentMatcher, CommandContentMatcher]);
|
|
135
137
|
expect(result).to.deep.equal([
|
|
136
138
|
new CommandChatResponseContentImpl('MY_SPECIAL_COMMAND'),
|
|
137
139
|
new MarkdownChatResponseContentImpl('\nHello **World**\n'),
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
*/
|
|
16
|
-
import { ChatResponseContent } from './chat-model';
|
|
16
|
+
import { ChatRequestModelImpl, ChatResponseContent } from './chat-model';
|
|
17
17
|
import { CodeContentMatcher, MarkdownContentFactory, ResponseContentFactory, ResponseContentMatcher } from './response-content-matcher';
|
|
18
18
|
|
|
19
19
|
interface Match {
|
|
@@ -24,6 +24,7 @@ interface Match {
|
|
|
24
24
|
|
|
25
25
|
export function parseContents(
|
|
26
26
|
text: string,
|
|
27
|
+
request: ChatRequestModelImpl,
|
|
27
28
|
contentMatchers: ResponseContentMatcher[] = [CodeContentMatcher],
|
|
28
29
|
defaultContentFactory: ResponseContentFactory = MarkdownContentFactory
|
|
29
30
|
): ChatResponseContent[] {
|
|
@@ -36,7 +37,7 @@ export function parseContents(
|
|
|
36
37
|
if (!match) {
|
|
37
38
|
// Add the remaining text as default content
|
|
38
39
|
if (remainingText.length > 0) {
|
|
39
|
-
result.push(defaultContentFactory(remainingText));
|
|
40
|
+
result.push(defaultContentFactory(remainingText, request));
|
|
40
41
|
}
|
|
41
42
|
break;
|
|
42
43
|
}
|
|
@@ -45,11 +46,11 @@ export function parseContents(
|
|
|
45
46
|
if (match.index > 0) {
|
|
46
47
|
const precedingContent = remainingText.substring(0, match.index);
|
|
47
48
|
if (precedingContent.trim().length > 0) {
|
|
48
|
-
result.push(defaultContentFactory(precedingContent));
|
|
49
|
+
result.push(defaultContentFactory(precedingContent, request));
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
// 2. Add the matched content object
|
|
52
|
-
result.push(match.matcher.contentFactory(match.content));
|
|
53
|
+
result.push(match.matcher.contentFactory(match.content, request));
|
|
53
54
|
// Update currentIndex to the end of the end of the match
|
|
54
55
|
// And continue with the search after the end of the match
|
|
55
56
|
currentIndex += match.index + match.content.length;
|
|
@@ -14,13 +14,14 @@
|
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
*/
|
|
16
16
|
import {
|
|
17
|
+
ChatRequestModelImpl,
|
|
17
18
|
ChatResponseContent,
|
|
18
19
|
CodeChatResponseContentImpl,
|
|
19
20
|
MarkdownChatResponseContentImpl
|
|
20
21
|
} from './chat-model';
|
|
21
22
|
import { injectable } from '@theia/core/shared/inversify';
|
|
22
23
|
|
|
23
|
-
export type ResponseContentFactory = (content: string) => ChatResponseContent;
|
|
24
|
+
export type ResponseContentFactory = (content: string, request: ChatRequestModelImpl) => ChatResponseContent;
|
|
24
25
|
|
|
25
26
|
export const MarkdownContentFactory: ResponseContentFactory = (content: string) =>
|
|
26
27
|
new MarkdownChatResponseContentImpl(content);
|
|
@@ -33,8 +34,8 @@ export const MarkdownContentFactory: ResponseContentFactory = (content: string)
|
|
|
33
34
|
*/
|
|
34
35
|
@injectable()
|
|
35
36
|
export class DefaultResponseContentFactory {
|
|
36
|
-
create(content: string): ChatResponseContent {
|
|
37
|
-
return MarkdownContentFactory(content);
|
|
37
|
+
create(content: string, request: ChatRequestModelImpl): ChatResponseContent {
|
|
38
|
+
return MarkdownContentFactory(content, request);
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -23,7 +23,9 @@ import { AbstractStreamParsingChatAgent, ChatAgent, SystemMessageDescription } f
|
|
|
23
23
|
|
|
24
24
|
export const universalTemplate: PromptTemplate = {
|
|
25
25
|
id: 'universal-system',
|
|
26
|
-
template:
|
|
26
|
+
template: `{{!-- Made improvements or adaptations to this prompt template? We’d love for you to share it with the community! Contribute back here:
|
|
27
|
+
https://github.com/eclipse-theia/theia/discussions/new?category=prompt-template-contribution --}}
|
|
28
|
+
# Instructions
|
|
27
29
|
|
|
28
30
|
You are an AI assistant integrated into the Theia IDE, specifically designed to help software developers by
|
|
29
31
|
providing concise and accurate answers to programming-related questions. Your role is to enhance the
|
|
@@ -76,6 +78,12 @@ simple solutions.
|
|
|
76
78
|
`
|
|
77
79
|
};
|
|
78
80
|
|
|
81
|
+
export const universalTemplateVariant: PromptTemplate = {
|
|
82
|
+
id: 'universal-system-empty',
|
|
83
|
+
template: '',
|
|
84
|
+
variantOf: universalTemplate.id,
|
|
85
|
+
};
|
|
86
|
+
|
|
79
87
|
@injectable()
|
|
80
88
|
export class UniversalChatAgent extends AbstractStreamParsingChatAgent implements ChatAgent {
|
|
81
89
|
name: string;
|
|
@@ -96,7 +104,7 @@ export class UniversalChatAgent extends AbstractStreamParsingChatAgent implement
|
|
|
96
104
|
+ 'questions the user might ask. The universal agent currently does not have any context by default, i.e. it cannot '
|
|
97
105
|
+ 'access the current user context or the workspace.';
|
|
98
106
|
this.variables = [];
|
|
99
|
-
this.promptTemplates = [universalTemplate];
|
|
107
|
+
this.promptTemplates = [universalTemplate, universalTemplateVariant];
|
|
100
108
|
this.functions = [];
|
|
101
109
|
this.agentSpecificVariables = [];
|
|
102
110
|
}
|