@theia/ai-chat 1.46.0-next.241
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 +31 -0
- package/lib/browser/ai-chat-frontend-module.d.ts +4 -0
- package/lib/browser/ai-chat-frontend-module.d.ts.map +1 -0
- package/lib/browser/ai-chat-frontend-module.js +79 -0
- package/lib/browser/ai-chat-frontend-module.js.map +1 -0
- package/lib/browser/ai-chat-preferences.d.ts +4 -0
- package/lib/browser/ai-chat-preferences.d.ts.map +1 -0
- package/lib/browser/ai-chat-preferences.js +32 -0
- package/lib/browser/ai-chat-preferences.js.map +1 -0
- package/lib/browser/custom-agent-factory.d.ts +4 -0
- package/lib/browser/custom-agent-factory.d.ts.map +1 -0
- package/lib/browser/custom-agent-factory.js +20 -0
- package/lib/browser/custom-agent-factory.js.map +1 -0
- package/lib/browser/custom-agent-frontend-application-contribution.d.ts +13 -0
- package/lib/browser/custom-agent-frontend-application-contribution.d.ts.map +1 -0
- package/lib/browser/custom-agent-frontend-application-contribution.js +82 -0
- package/lib/browser/custom-agent-frontend-application-contribution.js.map +1 -0
- package/lib/browser/frontend-chat-service.d.ts +8 -0
- package/lib/browser/frontend-chat-service.d.ts.map +1 -0
- package/lib/browser/frontend-chat-service.js +67 -0
- package/lib/browser/frontend-chat-service.js.map +1 -0
- package/lib/common/chat-agent-service.d.ts +45 -0
- package/lib/common/chat-agent-service.d.ts.map +1 -0
- package/lib/common/chat-agent-service.js +78 -0
- package/lib/common/chat-agent-service.js.map +1 -0
- package/lib/common/chat-agents-variable-contribution.d.ts +17 -0
- package/lib/common/chat-agents-variable-contribution.d.ts.map +1 -0
- package/lib/common/chat-agents-variable-contribution.js +51 -0
- package/lib/common/chat-agents-variable-contribution.js.map +1 -0
- package/lib/common/chat-agents.d.ts +108 -0
- package/lib/common/chat-agents.d.ts.map +1 -0
- package/lib/common/chat-agents.js +321 -0
- package/lib/common/chat-agents.js.map +1 -0
- 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 +393 -0
- package/lib/common/chat-model.d.ts.map +1 -0
- package/lib/common/chat-model.js +612 -0
- package/lib/common/chat-model.js.map +1 -0
- package/lib/common/chat-request-parser.d.ts +20 -0
- package/lib/common/chat-request-parser.d.ts.map +1 -0
- package/lib/common/chat-request-parser.js +158 -0
- package/lib/common/chat-request-parser.js.map +1 -0
- package/lib/common/chat-request-parser.spec.d.ts +2 -0
- package/lib/common/chat-request-parser.spec.d.ts.map +1 -0
- package/lib/common/chat-request-parser.spec.js +108 -0
- package/lib/common/chat-request-parser.spec.js.map +1 -0
- package/lib/common/chat-service.d.ts +72 -0
- package/lib/common/chat-service.d.ts.map +1 -0
- package/lib/common/chat-service.js +170 -0
- package/lib/common/chat-service.js.map +1 -0
- package/lib/common/command-chat-agents.d.ts +33 -0
- package/lib/common/command-chat-agents.d.ts.map +1 -0
- package/lib/common/command-chat-agents.js +329 -0
- package/lib/common/command-chat-agents.js.map +1 -0
- package/lib/common/custom-chat-agent.d.ts +14 -0
- package/lib/common/custom-chat-agent.d.ts.map +1 -0
- package/lib/common/custom-chat-agent.js +43 -0
- package/lib/common/custom-chat-agent.js.map +1 -0
- package/lib/common/index.d.ts +12 -0
- package/lib/common/index.d.ts.map +1 -0
- package/lib/common/index.js +30 -0
- package/lib/common/index.js.map +1 -0
- package/lib/common/o1-chat-agent.d.ts +13 -0
- package/lib/common/o1-chat-agent.d.ts.map +1 -0
- package/lib/common/o1-chat-agent.js +45 -0
- package/lib/common/o1-chat-agent.js.map +1 -0
- package/lib/common/orchestrator-chat-agent.d.ts +22 -0
- package/lib/common/orchestrator-chat-agent.d.ts.map +1 -0
- package/lib/common/orchestrator-chat-agent.js +167 -0
- package/lib/common/orchestrator-chat-agent.js.map +1 -0
- package/lib/common/parse-contents.d.ts +11 -0
- package/lib/common/parse-contents.d.ts.map +1 -0
- package/lib/common/parse-contents.js +67 -0
- package/lib/common/parse-contents.js.map +1 -0
- package/lib/common/parse-contents.spec.d.ts +9 -0
- package/lib/common/parse-contents.spec.d.ts.map +1 -0
- package/lib/common/parse-contents.spec.js +134 -0
- package/lib/common/parse-contents.spec.js.map +1 -0
- package/lib/common/parsed-chat-request.d.ts +66 -0
- package/lib/common/parsed-chat-request.d.ts.map +1 -0
- package/lib/common/parsed-chat-request.js +83 -0
- package/lib/common/parsed-chat-request.js.map +1 -0
- package/lib/common/response-content-matcher.d.ts +63 -0
- package/lib/common/response-content-matcher.d.ts.map +1 -0
- package/lib/common/response-content-matcher.js +86 -0
- package/lib/common/response-content-matcher.js.map +1 -0
- package/lib/common/universal-chat-agent.d.ts +16 -0
- package/lib/common/universal-chat-agent.d.ts.map +1 -0
- package/lib/common/universal-chat-agent.js +109 -0
- package/lib/common/universal-chat-agent.js.map +1 -0
- package/package.json +54 -0
- package/src/browser/ai-chat-frontend-module.ts +98 -0
- package/src/browser/ai-chat-preferences.ts +32 -0
- package/src/browser/custom-agent-factory.ts +20 -0
- package/src/browser/custom-agent-frontend-application-contribution.ts +73 -0
- package/src/browser/frontend-chat-service.ts +66 -0
- package/src/common/chat-agent-service.ts +100 -0
- package/src/common/chat-agents-variable-contribution.ts +81 -0
- package/src/common/chat-agents.ts +392 -0
- package/src/common/chat-history-entry.ts +47 -0
- package/src/common/chat-model-util.ts +44 -0
- package/src/common/chat-model.ts +889 -0
- package/src/common/chat-request-parser.spec.ts +120 -0
- package/src/common/chat-request-parser.ts +220 -0
- package/src/common/chat-service.ts +236 -0
- package/src/common/command-chat-agents.ts +354 -0
- package/src/common/custom-chat-agent.ts +44 -0
- package/src/common/index.ts +26 -0
- package/src/common/o1-chat-agent.ts +51 -0
- package/src/common/orchestrator-chat-agent.ts +179 -0
- package/src/common/parse-contents.spec.ts +144 -0
- package/src/common/parse-contents.ts +93 -0
- package/src/common/parsed-chat-request.ts +112 -0
- package/src/common/response-content-matcher.ts +103 -0
- package/src/common/universal-chat-agent.ts +117 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 EclipseSource GmbH.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { expect } from 'chai';
|
|
18
|
+
import { ChatRequestModelImpl, ChatResponseContent, CodeChatResponseContentImpl, MarkdownChatResponseContentImpl } from './chat-model';
|
|
19
|
+
import { parseContents } from './parse-contents';
|
|
20
|
+
import { CodeContentMatcher, ResponseContentMatcher } from './response-content-matcher';
|
|
21
|
+
|
|
22
|
+
export class CommandChatResponseContentImpl implements ChatResponseContent {
|
|
23
|
+
constructor(public readonly command: string) { }
|
|
24
|
+
kind = 'command';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const CommandContentMatcher: ResponseContentMatcher = {
|
|
28
|
+
start: /^<command>$/m,
|
|
29
|
+
end: /^<\/command>$/m,
|
|
30
|
+
contentFactory: (content: string) => {
|
|
31
|
+
const code = content.replace(/^<command>\n|<\/command>$/g, '');
|
|
32
|
+
return new CommandChatResponseContentImpl(code.trim());
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const fakeRequest = {} as ChatRequestModelImpl;
|
|
37
|
+
|
|
38
|
+
describe('parseContents', () => {
|
|
39
|
+
it('should parse code content', () => {
|
|
40
|
+
const text = '```typescript\nconsole.log("Hello World");\n```';
|
|
41
|
+
const result = parseContents(text, fakeRequest);
|
|
42
|
+
expect(result).to.deep.equal([new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript')]);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should parse markdown content', () => {
|
|
46
|
+
const text = 'Hello **World**';
|
|
47
|
+
const result = parseContents(text, fakeRequest);
|
|
48
|
+
expect(result).to.deep.equal([new MarkdownChatResponseContentImpl('Hello **World**')]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should parse multiple content blocks', () => {
|
|
52
|
+
const text = '```typescript\nconsole.log("Hello World");\n```\nHello **World**';
|
|
53
|
+
const result = parseContents(text, fakeRequest);
|
|
54
|
+
expect(result).to.deep.equal([
|
|
55
|
+
new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
|
|
56
|
+
new MarkdownChatResponseContentImpl('\nHello **World**')
|
|
57
|
+
]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should parse multiple content blocks with different languages', () => {
|
|
61
|
+
const text = '```typescript\nconsole.log("Hello World");\n```\n```python\nprint("Hello World")\n```';
|
|
62
|
+
const result = parseContents(text, fakeRequest);
|
|
63
|
+
expect(result).to.deep.equal([
|
|
64
|
+
new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
|
|
65
|
+
new CodeChatResponseContentImpl('print("Hello World")', 'python')
|
|
66
|
+
]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should parse multiple content blocks with different languages and markdown', () => {
|
|
70
|
+
const text = '```typescript\nconsole.log("Hello World");\n```\nHello **World**\n```python\nprint("Hello World")\n```';
|
|
71
|
+
const result = parseContents(text, fakeRequest);
|
|
72
|
+
expect(result).to.deep.equal([
|
|
73
|
+
new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
|
|
74
|
+
new MarkdownChatResponseContentImpl('\nHello **World**\n'),
|
|
75
|
+
new CodeChatResponseContentImpl('print("Hello World")', 'python')
|
|
76
|
+
]);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should parse content blocks with empty content', () => {
|
|
80
|
+
const text = '```typescript\n```\nHello **World**\n```python\nprint("Hello World")\n```';
|
|
81
|
+
const result = parseContents(text, fakeRequest);
|
|
82
|
+
expect(result).to.deep.equal([
|
|
83
|
+
new CodeChatResponseContentImpl('', 'typescript'),
|
|
84
|
+
new MarkdownChatResponseContentImpl('\nHello **World**\n'),
|
|
85
|
+
new CodeChatResponseContentImpl('print("Hello World")', 'python')
|
|
86
|
+
]);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should parse content with markdown, code, and markdown', () => {
|
|
90
|
+
const text = 'Hello **World**\n```typescript\nconsole.log("Hello World");\n```\nGoodbye **World**';
|
|
91
|
+
const result = parseContents(text, fakeRequest);
|
|
92
|
+
expect(result).to.deep.equal([
|
|
93
|
+
new MarkdownChatResponseContentImpl('Hello **World**\n'),
|
|
94
|
+
new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
|
|
95
|
+
new MarkdownChatResponseContentImpl('\nGoodbye **World**')
|
|
96
|
+
]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should handle text with no special content', () => {
|
|
100
|
+
const text = 'Just some plain text.';
|
|
101
|
+
const result = parseContents(text, fakeRequest);
|
|
102
|
+
expect(result).to.deep.equal([new MarkdownChatResponseContentImpl('Just some plain text.')]);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should handle text with only start code block', () => {
|
|
106
|
+
const text = '```typescript\nconsole.log("Hello World");';
|
|
107
|
+
const result = parseContents(text, fakeRequest);
|
|
108
|
+
expect(result).to.deep.equal([new MarkdownChatResponseContentImpl('```typescript\nconsole.log("Hello World");')]);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should handle text with only end code block', () => {
|
|
112
|
+
const text = 'console.log("Hello World");\n```';
|
|
113
|
+
const result = parseContents(text, fakeRequest);
|
|
114
|
+
expect(result).to.deep.equal([new MarkdownChatResponseContentImpl('console.log("Hello World");\n```')]);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should handle text with unmatched code block', () => {
|
|
118
|
+
const text = '```typescript\nconsole.log("Hello World");\n```\n```python\nprint("Hello World")';
|
|
119
|
+
const result = parseContents(text, fakeRequest);
|
|
120
|
+
expect(result).to.deep.equal([
|
|
121
|
+
new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
|
|
122
|
+
new MarkdownChatResponseContentImpl('\n```python\nprint("Hello World")')
|
|
123
|
+
]);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('should parse code block without newline after language', () => {
|
|
127
|
+
const text = '```typescript console.log("Hello World");```';
|
|
128
|
+
const result = parseContents(text, fakeRequest);
|
|
129
|
+
expect(result).to.deep.equal([
|
|
130
|
+
new MarkdownChatResponseContentImpl('```typescript console.log("Hello World");```')
|
|
131
|
+
]);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should parse with matches of multiple different matchers and default', () => {
|
|
135
|
+
const text = '<command>\nMY_SPECIAL_COMMAND\n</command>\nHello **World**\n```python\nprint("Hello World")\n```\n<command>\nMY_SPECIAL_COMMAND2\n</command>';
|
|
136
|
+
const result = parseContents(text, fakeRequest, [CodeContentMatcher, CommandContentMatcher]);
|
|
137
|
+
expect(result).to.deep.equal([
|
|
138
|
+
new CommandChatResponseContentImpl('MY_SPECIAL_COMMAND'),
|
|
139
|
+
new MarkdownChatResponseContentImpl('\nHello **World**\n'),
|
|
140
|
+
new CodeChatResponseContentImpl('print("Hello World")', 'python'),
|
|
141
|
+
new CommandChatResponseContentImpl('MY_SPECIAL_COMMAND2'),
|
|
142
|
+
]);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
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 { ChatRequestModelImpl, ChatResponseContent } from './chat-model';
|
|
17
|
+
import { CodeContentMatcher, MarkdownContentFactory, ResponseContentFactory, ResponseContentMatcher } from './response-content-matcher';
|
|
18
|
+
|
|
19
|
+
interface Match {
|
|
20
|
+
matcher: ResponseContentMatcher;
|
|
21
|
+
index: number;
|
|
22
|
+
content: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function parseContents(
|
|
26
|
+
text: string,
|
|
27
|
+
request: ChatRequestModelImpl,
|
|
28
|
+
contentMatchers: ResponseContentMatcher[] = [CodeContentMatcher],
|
|
29
|
+
defaultContentFactory: ResponseContentFactory = MarkdownContentFactory
|
|
30
|
+
): ChatResponseContent[] {
|
|
31
|
+
const result: ChatResponseContent[] = [];
|
|
32
|
+
|
|
33
|
+
let currentIndex = 0;
|
|
34
|
+
while (currentIndex < text.length) {
|
|
35
|
+
const remainingText = text.substring(currentIndex);
|
|
36
|
+
const match = findFirstMatch(contentMatchers, remainingText);
|
|
37
|
+
if (!match) {
|
|
38
|
+
// Add the remaining text as default content
|
|
39
|
+
if (remainingText.length > 0) {
|
|
40
|
+
result.push(defaultContentFactory(remainingText, request));
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
// We have a match
|
|
45
|
+
// 1. Add preceding text as default content
|
|
46
|
+
if (match.index > 0) {
|
|
47
|
+
const precedingContent = remainingText.substring(0, match.index);
|
|
48
|
+
if (precedingContent.trim().length > 0) {
|
|
49
|
+
result.push(defaultContentFactory(precedingContent, request));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// 2. Add the matched content object
|
|
53
|
+
result.push(match.matcher.contentFactory(match.content, request));
|
|
54
|
+
// Update currentIndex to the end of the end of the match
|
|
55
|
+
// And continue with the search after the end of the match
|
|
56
|
+
currentIndex += match.index + match.content.length;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function findFirstMatch(contentMatchers: ResponseContentMatcher[], text: string): Match | undefined {
|
|
63
|
+
let firstMatch: { matcher: ResponseContentMatcher, index: number, content: string } | undefined;
|
|
64
|
+
for (const matcher of contentMatchers) {
|
|
65
|
+
const startMatch = matcher.start.exec(text);
|
|
66
|
+
if (!startMatch) {
|
|
67
|
+
// No start match found, try next matcher.
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const endOfStartMatch = startMatch.index + startMatch[0].length;
|
|
71
|
+
if (endOfStartMatch >= text.length) {
|
|
72
|
+
// There is no text after the start match.
|
|
73
|
+
// No need to search for the end match yet, try next matcher.
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const remainingTextAfterStartMatch = text.substring(endOfStartMatch);
|
|
77
|
+
const endMatch = matcher.end.exec(remainingTextAfterStartMatch);
|
|
78
|
+
if (!endMatch) {
|
|
79
|
+
// No end match found, try next matcher.
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
// Found start and end match.
|
|
83
|
+
// Record the full match, if it is the earliest found so far.
|
|
84
|
+
const index = startMatch.index;
|
|
85
|
+
const contentEnd = index + startMatch[0].length + endMatch.index + endMatch[0].length;
|
|
86
|
+
const content = text.substring(index, contentEnd);
|
|
87
|
+
if (!firstMatch || index < firstMatch.index) {
|
|
88
|
+
firstMatch = { matcher, index, content };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return firstMatch;
|
|
92
|
+
}
|
|
93
|
+
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 EclipseSource GmbH.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
/*---------------------------------------------------------------------------------------------
|
|
17
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
18
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
19
|
+
*--------------------------------------------------------------------------------------------*/
|
|
20
|
+
// Partially copied from https://github.com/microsoft/vscode/blob/a2cab7255c0df424027be05d58e1b7b941f4ea60/src/vs/workbench/contrib/chat/common/chatParserTypes.ts
|
|
21
|
+
// Partially copied from https://github.com/microsoft/vscode/blob/a2cab7255c0df424027be05d58e1b7b941f4ea60/src/vs/editor/common/core/offsetRange.ts
|
|
22
|
+
|
|
23
|
+
import { AIVariable, ResolvedAIVariable, ToolRequest, toolRequestToPromptText } from '@theia/ai-core';
|
|
24
|
+
import { ChatRequest } from './chat-model';
|
|
25
|
+
|
|
26
|
+
export const chatVariableLeader = '#';
|
|
27
|
+
export const chatAgentLeader = '@';
|
|
28
|
+
export const chatFunctionLeader = '~';
|
|
29
|
+
export const chatSubcommandLeader = '/';
|
|
30
|
+
|
|
31
|
+
/**********************
|
|
32
|
+
* INTERFACES AND TYPE GUARDS
|
|
33
|
+
**********************/
|
|
34
|
+
|
|
35
|
+
export interface OffsetRange {
|
|
36
|
+
readonly start: number;
|
|
37
|
+
readonly endExclusive: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ParsedChatRequest {
|
|
41
|
+
readonly request: ChatRequest;
|
|
42
|
+
readonly parts: ParsedChatRequestPart[];
|
|
43
|
+
readonly toolRequests: Map<string, ToolRequest>;
|
|
44
|
+
readonly variables: Map<string, AIVariable>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ParsedChatRequestPart {
|
|
48
|
+
readonly kind: string;
|
|
49
|
+
/**
|
|
50
|
+
* The text as represented in the ChatRequest
|
|
51
|
+
*/
|
|
52
|
+
readonly text: string;
|
|
53
|
+
/**
|
|
54
|
+
* The text as will be sent to the LLM
|
|
55
|
+
*/
|
|
56
|
+
readonly promptText: string;
|
|
57
|
+
|
|
58
|
+
readonly range: OffsetRange;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export class ParsedChatRequestTextPart implements ParsedChatRequestPart {
|
|
62
|
+
readonly kind: 'text';
|
|
63
|
+
|
|
64
|
+
constructor(readonly range: OffsetRange, readonly text: string) { }
|
|
65
|
+
|
|
66
|
+
get promptText(): string {
|
|
67
|
+
return this.text;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export class ParsedChatRequestVariablePart implements ParsedChatRequestPart {
|
|
72
|
+
readonly kind: 'var';
|
|
73
|
+
|
|
74
|
+
public resolution: ResolvedAIVariable;
|
|
75
|
+
|
|
76
|
+
constructor(readonly range: OffsetRange, readonly variableName: string, readonly variableArg: string | undefined) { }
|
|
77
|
+
|
|
78
|
+
get text(): string {
|
|
79
|
+
const argPart = this.variableArg ? `:${this.variableArg}` : '';
|
|
80
|
+
return `${chatVariableLeader}${this.variableName}${argPart}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get promptText(): string {
|
|
84
|
+
return this.resolution?.value ?? this.text;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export class ParsedChatRequestFunctionPart implements ParsedChatRequestPart {
|
|
89
|
+
readonly kind: 'function';
|
|
90
|
+
constructor(readonly range: OffsetRange, readonly toolRequest: ToolRequest) { }
|
|
91
|
+
|
|
92
|
+
get text(): string {
|
|
93
|
+
return `${chatFunctionLeader}${this.toolRequest.id}`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get promptText(): string {
|
|
97
|
+
return toolRequestToPromptText(this.toolRequest);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export class ParsedChatRequestAgentPart implements ParsedChatRequestPart {
|
|
102
|
+
readonly kind: 'agent';
|
|
103
|
+
constructor(readonly range: OffsetRange, readonly agentId: string, readonly agentName: string) { }
|
|
104
|
+
|
|
105
|
+
get text(): string {
|
|
106
|
+
return `${chatAgentLeader}${this.agentName}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
get promptText(): string {
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
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 {
|
|
17
|
+
ChatRequestModelImpl,
|
|
18
|
+
ChatResponseContent,
|
|
19
|
+
CodeChatResponseContentImpl,
|
|
20
|
+
MarkdownChatResponseContentImpl
|
|
21
|
+
} from './chat-model';
|
|
22
|
+
import { injectable } from '@theia/core/shared/inversify';
|
|
23
|
+
|
|
24
|
+
export type ResponseContentFactory = (content: string, request: ChatRequestModelImpl) => ChatResponseContent;
|
|
25
|
+
|
|
26
|
+
export const MarkdownContentFactory: ResponseContentFactory = (content: string) =>
|
|
27
|
+
new MarkdownChatResponseContentImpl(content);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Default response content factory used if no other `ResponseContentMatcher` applies.
|
|
31
|
+
* By default, this factory creates a markdown content object.
|
|
32
|
+
*
|
|
33
|
+
* @see MarkdownChatResponseContentImpl
|
|
34
|
+
*/
|
|
35
|
+
@injectable()
|
|
36
|
+
export class DefaultResponseContentFactory {
|
|
37
|
+
create(content: string, request: ChatRequestModelImpl): ChatResponseContent {
|
|
38
|
+
return MarkdownContentFactory(content, request);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Clients can contribute response content matchers to parse a chat response into specific
|
|
44
|
+
* `ChatResponseContent` instances.
|
|
45
|
+
*/
|
|
46
|
+
export interface ResponseContentMatcher {
|
|
47
|
+
/** Regular expression for finding the start delimiter. */
|
|
48
|
+
start: RegExp;
|
|
49
|
+
/** Regular expression for finding the start delimiter. */
|
|
50
|
+
end: RegExp;
|
|
51
|
+
/**
|
|
52
|
+
* The factory creating a response content from the matching content,
|
|
53
|
+
* from start index to end index of the match (including delimiters).
|
|
54
|
+
*/
|
|
55
|
+
contentFactory: ResponseContentFactory;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const CodeContentMatcher: ResponseContentMatcher = {
|
|
59
|
+
start: /^```.*?$/m,
|
|
60
|
+
end: /^```$/m,
|
|
61
|
+
contentFactory: (content: string) => {
|
|
62
|
+
const language = content.match(/^```(\w+)/)?.[1] || '';
|
|
63
|
+
const code = content.replace(/^```(\w+)\n|```$/g, '');
|
|
64
|
+
return new CodeChatResponseContentImpl(code.trim(), language);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Clients can contribute response content matchers to parse the response content.
|
|
70
|
+
*
|
|
71
|
+
* The default chat user interface will collect all contributed matchers and use them
|
|
72
|
+
* to parse the response into structured content parts (e.g. code blocks, markdown blocks),
|
|
73
|
+
* which are then rendered with a `ChatResponsePartRenderer` registered for the respective
|
|
74
|
+
* content part type.
|
|
75
|
+
*
|
|
76
|
+
* ### Example
|
|
77
|
+
* ```ts
|
|
78
|
+
* bind(ResponseContentMatcherProvider).to(MyResponseContentMatcherProvider);
|
|
79
|
+
* ...
|
|
80
|
+
* @injectable()
|
|
81
|
+
* export class MyResponseContentMatcherProvider implements ResponseContentMatcherProvider {
|
|
82
|
+
* readonly matchers: ResponseContentMatcher[] = [{
|
|
83
|
+
* start: /^<command>$/m,
|
|
84
|
+
* end: /^</command>$/m,
|
|
85
|
+
* contentFactory: (content: string) => {
|
|
86
|
+
* const command = content.replace(/^<command>\n|<\/command>$/g, '');
|
|
87
|
+
* return new MyChatResponseContentImpl(command.trim());
|
|
88
|
+
* }
|
|
89
|
+
* }];
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @see ResponseContentMatcher
|
|
94
|
+
*/
|
|
95
|
+
export const ResponseContentMatcherProvider = Symbol('ResponseContentMatcherProvider');
|
|
96
|
+
export interface ResponseContentMatcherProvider {
|
|
97
|
+
readonly matchers: ResponseContentMatcher[];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@injectable()
|
|
101
|
+
export class DefaultResponseContentMatcherProvider implements ResponseContentMatcherProvider {
|
|
102
|
+
readonly matchers: ResponseContentMatcher[] = [CodeContentMatcher];
|
|
103
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 EclipseSource GmbH.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { AgentSpecificVariables } from '@theia/ai-core';
|
|
18
|
+
import {
|
|
19
|
+
PromptTemplate
|
|
20
|
+
} from '@theia/ai-core/lib/common';
|
|
21
|
+
import { injectable } from '@theia/core/shared/inversify';
|
|
22
|
+
import { AbstractStreamParsingChatAgent, ChatAgent, SystemMessageDescription } from './chat-agents';
|
|
23
|
+
|
|
24
|
+
export const universalTemplate: PromptTemplate = {
|
|
25
|
+
id: 'universal-system',
|
|
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
|
|
29
|
+
|
|
30
|
+
You are an AI assistant integrated into the Theia IDE, specifically designed to help software developers by
|
|
31
|
+
providing concise and accurate answers to programming-related questions. Your role is to enhance the
|
|
32
|
+
developer's productivity by offering quick solutions, explanations, and best practices.
|
|
33
|
+
Keep responses short and to the point, focusing on delivering valuable insights, best practices and
|
|
34
|
+
simple solutions.
|
|
35
|
+
|
|
36
|
+
### Guidelines
|
|
37
|
+
|
|
38
|
+
1. **Understand Context:**
|
|
39
|
+
- Assess the context of the code or issue when available.
|
|
40
|
+
- Tailor responses to be relevant to the programming language, framework, or tools like Eclipse Theia.
|
|
41
|
+
- Ask clarifying questions if necessary to provide accurate assistance.
|
|
42
|
+
|
|
43
|
+
2. **Provide Clear Solutions:**
|
|
44
|
+
- Offer direct answers or code snippets that solve the problem or clarify the concept.
|
|
45
|
+
- Avoid lengthy explanations unless necessary for understanding.
|
|
46
|
+
|
|
47
|
+
3. **Promote Best Practices:**
|
|
48
|
+
- Suggest best practices and common patterns relevant to the question.
|
|
49
|
+
- Provide links to official documentation for further reading when applicable.
|
|
50
|
+
|
|
51
|
+
4. **Support Multiple Languages and Tools:**
|
|
52
|
+
- Be familiar with popular programming languages, frameworks, IDEs like Eclipse Theia, and command-line tools.
|
|
53
|
+
- Adapt advice based on the language, environment, or tools specified by the developer.
|
|
54
|
+
|
|
55
|
+
5. **Facilitate Learning:**
|
|
56
|
+
- Encourage learning by explaining why a solution works or why a particular approach is recommended.
|
|
57
|
+
- Keep explanations concise and educational.
|
|
58
|
+
|
|
59
|
+
6. **Maintain Professional Tone:**
|
|
60
|
+
- Communicate in a friendly, professional manner.
|
|
61
|
+
- Use technical jargon appropriately, ensuring clarity for the target audience.
|
|
62
|
+
|
|
63
|
+
7. **Stay on Topic:**
|
|
64
|
+
- Limit responses strictly to topics related to software development, frameworks, Eclipse Theia, terminal usage, and relevant technologies.
|
|
65
|
+
- Politely decline to answer questions unrelated to these areas by saying, "I'm here to assist with programming-related questions.
|
|
66
|
+
For other topics, please refer to a specialized source."
|
|
67
|
+
|
|
68
|
+
### Example Interactions
|
|
69
|
+
|
|
70
|
+
- **Question:** "What's the difference between \`let\` and \`var\` in JavaScript?"
|
|
71
|
+
**Answer:** "\`let\` is block-scoped, while \`var\` is function-scoped. Prefer \`let\` to avoid scope-related bugs."
|
|
72
|
+
|
|
73
|
+
- **Question:** "How do I handle exceptions in Java?"
|
|
74
|
+
**Answer:** "Use try-catch blocks: \`\`\`java try { /* code */ } catch (ExceptionType e) { /* handle exception */ }\`\`\`."
|
|
75
|
+
|
|
76
|
+
- **Question:** "What is the capital of France?"
|
|
77
|
+
**Answer:** "I'm here to assist with programming-related queries. For other topics, please refer to a specialized source."
|
|
78
|
+
`
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const universalTemplateVariant: PromptTemplate = {
|
|
82
|
+
id: 'universal-system-empty',
|
|
83
|
+
template: '',
|
|
84
|
+
variantOf: universalTemplate.id,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
@injectable()
|
|
88
|
+
export class UniversalChatAgent extends AbstractStreamParsingChatAgent implements ChatAgent {
|
|
89
|
+
name: string;
|
|
90
|
+
description: string;
|
|
91
|
+
variables: string[];
|
|
92
|
+
promptTemplates: PromptTemplate[];
|
|
93
|
+
readonly functions: string[];
|
|
94
|
+
readonly agentSpecificVariables: AgentSpecificVariables[];
|
|
95
|
+
|
|
96
|
+
constructor() {
|
|
97
|
+
super('Universal', [{
|
|
98
|
+
purpose: 'chat',
|
|
99
|
+
identifier: 'openai/gpt-4o',
|
|
100
|
+
}], 'chat');
|
|
101
|
+
this.name = 'Universal';
|
|
102
|
+
this.description = 'This agent is designed to help software developers by providing concise and accurate '
|
|
103
|
+
+ 'answers to general programming and software development questions. It is also the fall-back for any generic '
|
|
104
|
+
+ 'questions the user might ask. The universal agent currently does not have any context by default, i.e. it cannot '
|
|
105
|
+
+ 'access the current user context or the workspace.';
|
|
106
|
+
this.variables = [];
|
|
107
|
+
this.promptTemplates = [universalTemplate, universalTemplateVariant];
|
|
108
|
+
this.functions = [];
|
|
109
|
+
this.agentSpecificVariables = [];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
protected override async getSystemMessageDescription(): Promise<SystemMessageDescription | undefined> {
|
|
113
|
+
const resolvedPrompt = await this.promptService.getPrompt(universalTemplate.id);
|
|
114
|
+
return resolvedPrompt ? SystemMessageDescription.fromResolvedPromptTemplate(resolvedPrompt) : undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
}
|