@jupyterlite/ai 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/chat-handler.d.ts +10 -4
- package/lib/chat-handler.js +42 -10
- package/lib/completion-provider.d.ts +5 -18
- package/lib/completion-provider.js +8 -34
- package/lib/{llm-models/anthropic-completer.d.ts → default-providers/Anthropic/completer.d.ts} +1 -1
- package/lib/{llm-models/anthropic-completer.js → default-providers/Anthropic/completer.js} +1 -1
- package/lib/{llm-models/chrome-completer.d.ts → default-providers/ChromeAI/completer.d.ts} +1 -1
- package/lib/{llm-models/chrome-completer.js → default-providers/ChromeAI/completer.js} +1 -1
- package/lib/default-providers/ChromeAI/instructions.d.ts +2 -0
- package/lib/default-providers/ChromeAI/instructions.js +24 -0
- package/lib/{llm-models/codestral-completer.d.ts → default-providers/MistralAI/completer.d.ts} +1 -1
- package/lib/{llm-models/codestral-completer.js → default-providers/MistralAI/completer.js} +1 -1
- package/lib/default-providers/MistralAI/instructions.d.ts +2 -0
- package/lib/default-providers/MistralAI/instructions.js +16 -0
- package/lib/{llm-models/openai-completer.d.ts → default-providers/OpenAI/completer.d.ts} +1 -1
- package/lib/{llm-models/openai-completer.js → default-providers/OpenAI/completer.js} +1 -1
- package/lib/default-providers/index.d.ts +2 -0
- package/lib/default-providers/index.js +60 -0
- package/lib/index.d.ts +3 -3
- package/lib/index.js +51 -64
- package/lib/provider.d.ts +45 -17
- package/lib/provider.js +97 -41
- package/lib/settings/base.json +7 -0
- package/lib/settings/panel.d.ts +84 -0
- package/lib/settings/panel.js +267 -0
- package/lib/tokens.d.ts +103 -0
- package/lib/tokens.js +5 -0
- package/package.json +12 -5
- package/schema/provider-registry.json +23 -0
- package/src/chat-handler.ts +50 -13
- package/src/completion-provider.ts +13 -37
- package/src/{llm-models/anthropic-completer.ts → default-providers/Anthropic/completer.ts} +2 -2
- package/src/{llm-models/chrome-completer.ts → default-providers/ChromeAI/completer.ts} +3 -2
- package/src/default-providers/ChromeAI/instructions.ts +24 -0
- package/src/{llm-models/codestral-completer.ts → default-providers/MistralAI/completer.ts} +2 -2
- package/src/default-providers/MistralAI/instructions.ts +16 -0
- package/src/{llm-models/openai-completer.ts → default-providers/OpenAI/completer.ts} +2 -2
- package/src/default-providers/index.ts +71 -0
- package/src/index.ts +75 -77
- package/src/provider.ts +100 -43
- package/src/settings/panel.tsx +346 -0
- package/src/tokens.ts +112 -0
- package/style/base.css +4 -0
- package/lib/llm-models/index.d.ts +0 -3
- package/lib/llm-models/index.js +0 -3
- package/lib/llm-models/utils.d.ts +0 -16
- package/lib/llm-models/utils.js +0 -86
- package/lib/slash-commands.d.ts +0 -16
- package/lib/slash-commands.js +0 -25
- package/lib/token.d.ts +0 -13
- package/lib/token.js +0 -2
- package/schema/ai-provider.json +0 -17
- package/src/llm-models/index.ts +0 -3
- package/src/llm-models/utils.ts +0 -90
- package/src/slash-commands.tsx +0 -55
- package/src/token.ts +0 -19
- /package/lib/{llm-models/base-completer.d.ts → base-completer.d.ts} +0 -0
- /package/lib/{llm-models/base-completer.js → base-completer.js} +0 -0
- /package/lib/{_provider-settings/anthropic.json → default-providers/Anthropic/settings-schema.json} +0 -0
- /package/lib/{_provider-settings/chromeAI.json → default-providers/ChromeAI/settings-schema.json} +0 -0
- /package/lib/{_provider-settings/mistralAI.json → default-providers/MistralAI/settings-schema.json} +0 -0
- /package/lib/{_provider-settings/openAI.json → default-providers/OpenAI/settings-schema.json} +0 -0
- /package/src/{llm-models/base-completer.ts → base-completer.ts} +0 -0
- /package/src/{llm-models/svg.d.ts → global.d.ts} +0 -0
package/lib/chat-handler.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ChatModel, IChatHistory, IChatMessage, INewMessage } from '@jupyter/chat';
|
|
1
|
+
import { ChatCommand, ChatModel, IChatCommandProvider, IChatHistory, IChatMessage, IInputModel, INewMessage } from '@jupyter/chat';
|
|
2
2
|
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
3
|
-
import {
|
|
3
|
+
import { IAIProviderRegistry } from './tokens';
|
|
4
4
|
export type ConnectionMessage = {
|
|
5
5
|
type: 'connection';
|
|
6
6
|
client_id: string;
|
|
@@ -22,7 +22,7 @@ export declare class ChatHandler extends ChatModel {
|
|
|
22
22
|
getHistory(): Promise<IChatHistory>;
|
|
23
23
|
dispose(): void;
|
|
24
24
|
messageAdded(message: IChatMessage): void;
|
|
25
|
-
private
|
|
25
|
+
private _providerRegistry;
|
|
26
26
|
private _personaName;
|
|
27
27
|
private _prompt;
|
|
28
28
|
private _errorMessage;
|
|
@@ -31,6 +31,12 @@ export declare class ChatHandler extends ChatModel {
|
|
|
31
31
|
}
|
|
32
32
|
export declare namespace ChatHandler {
|
|
33
33
|
interface IOptions extends ChatModel.IOptions {
|
|
34
|
-
|
|
34
|
+
providerRegistry: IAIProviderRegistry;
|
|
35
|
+
}
|
|
36
|
+
class ClearCommandProvider implements IChatCommandProvider {
|
|
37
|
+
id: string;
|
|
38
|
+
private _slash_commands;
|
|
39
|
+
getChatCommands(inputModel: IInputModel): Promise<ChatCommand[]>;
|
|
40
|
+
handleChatCommand(command: ChatCommand, inputModel: IInputModel): Promise<void>;
|
|
35
41
|
}
|
|
36
42
|
}
|
package/lib/chat-handler.js
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
import { ChatModel } from '@jupyter/chat';
|
|
6
6
|
import { AIMessage, HumanMessage, mergeMessageRuns, SystemMessage } from '@langchain/core/messages';
|
|
7
7
|
import { UUID } from '@lumino/coreutils';
|
|
8
|
-
import { getErrorMessage } from './llm-models';
|
|
9
8
|
import { chatSystemPrompt } from './provider';
|
|
10
9
|
import { jupyternautLiteIcon } from './icons';
|
|
11
10
|
/**
|
|
@@ -21,15 +20,19 @@ export class ChatHandler extends ChatModel {
|
|
|
21
20
|
this._errorMessage = '';
|
|
22
21
|
this._history = { messages: [] };
|
|
23
22
|
this._defaultErrorMessage = 'AI provider not configured';
|
|
24
|
-
this.
|
|
25
|
-
this._prompt = chatSystemPrompt({
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
this._providerRegistry = options.providerRegistry;
|
|
24
|
+
this._prompt = chatSystemPrompt({
|
|
25
|
+
provider_name: this._providerRegistry.currentName
|
|
26
|
+
});
|
|
27
|
+
this._providerRegistry.providerChanged.connect(() => {
|
|
28
|
+
this._errorMessage = this._providerRegistry.chatError;
|
|
29
|
+
this._prompt = chatSystemPrompt({
|
|
30
|
+
provider_name: this._providerRegistry.currentName
|
|
31
|
+
});
|
|
29
32
|
});
|
|
30
33
|
}
|
|
31
34
|
get provider() {
|
|
32
|
-
return this.
|
|
35
|
+
return this._providerRegistry.currentChatModel;
|
|
33
36
|
}
|
|
34
37
|
/**
|
|
35
38
|
* Getter and setter for the persona name.
|
|
@@ -74,7 +77,7 @@ export class ChatHandler extends ChatModel {
|
|
|
74
77
|
type: 'msg'
|
|
75
78
|
};
|
|
76
79
|
this.messageAdded(msg);
|
|
77
|
-
if (this.
|
|
80
|
+
if (this._providerRegistry.currentChatModel === null) {
|
|
78
81
|
const errorMsg = {
|
|
79
82
|
id: UUID.uuid4(),
|
|
80
83
|
body: `**${this._errorMessage ? this._errorMessage : this._defaultErrorMessage}**`,
|
|
@@ -105,7 +108,7 @@ export class ChatHandler extends ChatModel {
|
|
|
105
108
|
};
|
|
106
109
|
let content = '';
|
|
107
110
|
try {
|
|
108
|
-
for await (const chunk of await this.
|
|
111
|
+
for await (const chunk of await this._providerRegistry.currentChatModel.stream(messages)) {
|
|
109
112
|
content += (_a = chunk.content) !== null && _a !== void 0 ? _a : chunk;
|
|
110
113
|
botMsg.body = content;
|
|
111
114
|
this.messageAdded(botMsg);
|
|
@@ -114,7 +117,7 @@ export class ChatHandler extends ChatModel {
|
|
|
114
117
|
return true;
|
|
115
118
|
}
|
|
116
119
|
catch (reason) {
|
|
117
|
-
const error =
|
|
120
|
+
const error = this._providerRegistry.formatErrorMessage(reason);
|
|
118
121
|
const errorMsg = {
|
|
119
122
|
id: UUID.uuid4(),
|
|
120
123
|
body: `**${error}**`,
|
|
@@ -139,3 +142,32 @@ export class ChatHandler extends ChatModel {
|
|
|
139
142
|
super.messageAdded(message);
|
|
140
143
|
}
|
|
141
144
|
}
|
|
145
|
+
(function (ChatHandler) {
|
|
146
|
+
class ClearCommandProvider {
|
|
147
|
+
constructor() {
|
|
148
|
+
this.id = '@jupyterlite/ai:clear-commands';
|
|
149
|
+
this._slash_commands = [
|
|
150
|
+
{
|
|
151
|
+
name: '/clear',
|
|
152
|
+
providerId: this.id,
|
|
153
|
+
replaceWith: '/clear',
|
|
154
|
+
description: 'Clear the chat'
|
|
155
|
+
}
|
|
156
|
+
];
|
|
157
|
+
}
|
|
158
|
+
async getChatCommands(inputModel) {
|
|
159
|
+
var _a, _b;
|
|
160
|
+
const match = (_b = (_a = inputModel.currentWord) === null || _a === void 0 ? void 0 : _a.match(/^\/\w*/)) === null || _b === void 0 ? void 0 : _b[0];
|
|
161
|
+
if (!match) {
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
const commands = this._slash_commands.filter(cmd => cmd.name.startsWith(match));
|
|
165
|
+
return commands;
|
|
166
|
+
}
|
|
167
|
+
async handleChatCommand(command, inputModel) {
|
|
168
|
+
// no handling needed because `replaceWith` is set in each command.
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
ChatHandler.ClearCommandProvider = ClearCommandProvider;
|
|
173
|
+
})(ChatHandler || (ChatHandler = {}));
|
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
import { CompletionHandler, IInlineCompletionContext, IInlineCompletionProvider } from '@jupyterlab/completer';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { IBaseCompleter, BaseCompleter } from './llm-models';
|
|
2
|
+
import { IBaseCompleter } from './base-completer';
|
|
3
|
+
import { IAIProviderRegistry } from './tokens';
|
|
5
4
|
/**
|
|
6
5
|
* The generic completion provider to register to the completion provider manager.
|
|
7
6
|
*/
|
|
8
7
|
export declare class CompletionProvider implements IInlineCompletionProvider {
|
|
9
8
|
readonly identifier = "@jupyterlite/ai";
|
|
10
9
|
constructor(options: CompletionProvider.IOptions);
|
|
11
|
-
/**
|
|
12
|
-
* Set the completer.
|
|
13
|
-
*
|
|
14
|
-
* @param name - the name of the completer.
|
|
15
|
-
* @param settings - The settings associated to the completer.
|
|
16
|
-
*/
|
|
17
|
-
setCompleter(name: string, settings: ReadonlyPartialJSONObject): void;
|
|
18
10
|
/**
|
|
19
11
|
* Get the current completer name.
|
|
20
12
|
*/
|
|
@@ -23,18 +15,13 @@ export declare class CompletionProvider implements IInlineCompletionProvider {
|
|
|
23
15
|
* Get the current completer.
|
|
24
16
|
*/
|
|
25
17
|
get completer(): IBaseCompleter | null;
|
|
26
|
-
/**
|
|
27
|
-
* Get the LLM completer.
|
|
28
|
-
*/
|
|
29
|
-
get llmCompleter(): BaseLanguageModel | null;
|
|
30
18
|
fetch(request: CompletionHandler.IRequest, context: IInlineCompletionContext): Promise<any>;
|
|
31
|
-
private
|
|
19
|
+
private _providerRegistry;
|
|
32
20
|
private _requestCompletion;
|
|
33
|
-
private _completer;
|
|
34
21
|
}
|
|
35
22
|
export declare namespace CompletionProvider {
|
|
36
|
-
interface IOptions
|
|
37
|
-
|
|
23
|
+
interface IOptions {
|
|
24
|
+
providerRegistry: IAIProviderRegistry;
|
|
38
25
|
requestCompletion: () => void;
|
|
39
26
|
}
|
|
40
27
|
}
|
|
@@ -1,57 +1,31 @@
|
|
|
1
|
-
import { getCompleter } from './llm-models';
|
|
2
1
|
/**
|
|
3
2
|
* The generic completion provider to register to the completion provider manager.
|
|
4
3
|
*/
|
|
5
4
|
export class CompletionProvider {
|
|
6
5
|
constructor(options) {
|
|
7
6
|
this.identifier = '@jupyterlite/ai';
|
|
8
|
-
this.
|
|
9
|
-
this._completer = null;
|
|
10
|
-
const { name, settings } = options;
|
|
7
|
+
this._providerRegistry = options.providerRegistry;
|
|
11
8
|
this._requestCompletion = options.requestCompletion;
|
|
12
|
-
this.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* Set the completer.
|
|
16
|
-
*
|
|
17
|
-
* @param name - the name of the completer.
|
|
18
|
-
* @param settings - The settings associated to the completer.
|
|
19
|
-
*/
|
|
20
|
-
setCompleter(name, settings) {
|
|
21
|
-
try {
|
|
22
|
-
this._completer = getCompleter(name, settings);
|
|
23
|
-
if (this._completer) {
|
|
24
|
-
this._completer.requestCompletion = this._requestCompletion;
|
|
9
|
+
this._providerRegistry.providerChanged.connect(() => {
|
|
10
|
+
if (this.completer) {
|
|
11
|
+
this.completer.requestCompletion = this._requestCompletion;
|
|
25
12
|
}
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
catch (e) {
|
|
29
|
-
this._completer = null;
|
|
30
|
-
this._name = 'None';
|
|
31
|
-
throw e;
|
|
32
|
-
}
|
|
13
|
+
});
|
|
33
14
|
}
|
|
34
15
|
/**
|
|
35
16
|
* Get the current completer name.
|
|
36
17
|
*/
|
|
37
18
|
get name() {
|
|
38
|
-
return this.
|
|
19
|
+
return this._providerRegistry.currentName;
|
|
39
20
|
}
|
|
40
21
|
/**
|
|
41
22
|
* Get the current completer.
|
|
42
23
|
*/
|
|
43
24
|
get completer() {
|
|
44
|
-
return this.
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Get the LLM completer.
|
|
48
|
-
*/
|
|
49
|
-
get llmCompleter() {
|
|
50
|
-
var _a;
|
|
51
|
-
return ((_a = this._completer) === null || _a === void 0 ? void 0 : _a.provider) || null;
|
|
25
|
+
return this._providerRegistry.currentCompleter;
|
|
52
26
|
}
|
|
53
27
|
async fetch(request, context) {
|
|
54
28
|
var _a;
|
|
55
|
-
return (_a = this.
|
|
29
|
+
return (_a = this.completer) === null || _a === void 0 ? void 0 : _a.fetch(request, context);
|
|
56
30
|
}
|
|
57
31
|
}
|
package/lib/{llm-models/anthropic-completer.d.ts → default-providers/Anthropic/completer.d.ts}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CompletionHandler, IInlineCompletionContext } from '@jupyterlab/completer';
|
|
2
2
|
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
3
|
-
import { BaseCompleter, IBaseCompleter } from '
|
|
3
|
+
import { BaseCompleter, IBaseCompleter } from '../../base-completer';
|
|
4
4
|
export declare class AnthropicCompleter implements IBaseCompleter {
|
|
5
5
|
constructor(options: BaseCompleter.IOptions);
|
|
6
6
|
get provider(): BaseChatModel;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ChatAnthropic } from '@langchain/anthropic';
|
|
2
2
|
import { AIMessage, SystemMessage } from '@langchain/core/messages';
|
|
3
|
-
import { COMPLETION_SYSTEM_PROMPT } from '
|
|
3
|
+
import { COMPLETION_SYSTEM_PROMPT } from '../../provider';
|
|
4
4
|
export class AnthropicCompleter {
|
|
5
5
|
constructor(options) {
|
|
6
6
|
this._prompt = COMPLETION_SYSTEM_PROMPT;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CompletionHandler, IInlineCompletionContext } from '@jupyterlab/completer';
|
|
2
2
|
import { LLM } from '@langchain/core/language_models/llms';
|
|
3
|
-
import { BaseCompleter, IBaseCompleter } from '
|
|
3
|
+
import { BaseCompleter, IBaseCompleter } from '../../base-completer';
|
|
4
4
|
export declare class ChromeCompleter implements IBaseCompleter {
|
|
5
5
|
constructor(options: BaseCompleter.IOptions);
|
|
6
6
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ChromeAI } from '@langchain/community/experimental/llms/chrome_ai';
|
|
2
2
|
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
|
|
3
|
-
import { COMPLETION_SYSTEM_PROMPT } from '
|
|
3
|
+
import { COMPLETION_SYSTEM_PROMPT } from '../../provider';
|
|
4
4
|
/**
|
|
5
5
|
* Regular expression to match the '```' string at the start of a string.
|
|
6
6
|
* So the completions returned by the LLM can still be kept after removing the code block formatting.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: "\n<i class=\"fas fa-exclamation-triangle\"></i> Support for ChromeAI is still experimental and only available in Google Chrome.\n\nYou can test ChromeAI is enabled in your browser by going to the following URL: <https://chromeai.org/>\n\nEnable the proper flags in Google Chrome.\n\n- chrome://flags/#prompt-api-for-gemini-nano\n - Select: `Enabled`\n- chrome://flags/#optimization-guide-on-device-model\n - Select: `Enabled BypassPrefRequirement`\n- chrome://components\n - Click `Check for Update` on Optimization Guide On Device Model to download the model\n- [Optional] chrome://flags/#text-safety-classifier\n\n<img src=\"https://github.com/user-attachments/assets/d48f46cc-52ee-4ce5-9eaf-c763cdbee04c\" alt=\"A screenshot showing how to enable the ChromeAI flag in Google Chrome\" width=\"500px\">\n\nThen restart Chrome for these changes to take effect.\n\n<i class=\"fas fa-exclamation-triangle\"></i> On first use, Chrome will download the on-device model, which can be as large as 22GB (according to their docs and at the time of writing).\nDuring the download, ChromeAI may not be available via the extension.\n\n<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i> For more information about Chrome Built-in AI: <https://developer.chrome.com/docs/ai/get-started>\n";
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export default `
|
|
2
|
+
<i class="fas fa-exclamation-triangle"></i> Support for ChromeAI is still experimental and only available in Google Chrome.
|
|
3
|
+
|
|
4
|
+
You can test ChromeAI is enabled in your browser by going to the following URL: <https://chromeai.org/>
|
|
5
|
+
|
|
6
|
+
Enable the proper flags in Google Chrome.
|
|
7
|
+
|
|
8
|
+
- chrome://flags/#prompt-api-for-gemini-nano
|
|
9
|
+
- Select: \`Enabled\`
|
|
10
|
+
- chrome://flags/#optimization-guide-on-device-model
|
|
11
|
+
- Select: \`Enabled BypassPrefRequirement\`
|
|
12
|
+
- chrome://components
|
|
13
|
+
- Click \`Check for Update\` on Optimization Guide On Device Model to download the model
|
|
14
|
+
- [Optional] chrome://flags/#text-safety-classifier
|
|
15
|
+
|
|
16
|
+
<img src="https://github.com/user-attachments/assets/d48f46cc-52ee-4ce5-9eaf-c763cdbee04c" alt="A screenshot showing how to enable the ChromeAI flag in Google Chrome" width="500px">
|
|
17
|
+
|
|
18
|
+
Then restart Chrome for these changes to take effect.
|
|
19
|
+
|
|
20
|
+
<i class="fas fa-exclamation-triangle"></i> On first use, Chrome will download the on-device model, which can be as large as 22GB (according to their docs and at the time of writing).
|
|
21
|
+
During the download, ChromeAI may not be available via the extension.
|
|
22
|
+
|
|
23
|
+
<i class="fa fa-info-circle" aria-hidden="true"></i> For more information about Chrome Built-in AI: <https://developer.chrome.com/docs/ai/get-started>
|
|
24
|
+
`;
|
package/lib/{llm-models/codestral-completer.d.ts → default-providers/MistralAI/completer.d.ts}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CompletionHandler, IInlineCompletionContext } from '@jupyterlab/completer';
|
|
2
2
|
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
3
|
-
import { BaseCompleter, IBaseCompleter } from '
|
|
3
|
+
import { BaseCompleter, IBaseCompleter } from '../../base-completer';
|
|
4
4
|
export declare class CodestralCompleter implements IBaseCompleter {
|
|
5
5
|
constructor(options: BaseCompleter.IOptions);
|
|
6
6
|
get provider(): BaseChatModel;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
|
|
2
2
|
import { ChatMistralAI } from '@langchain/mistralai';
|
|
3
3
|
import { Throttler } from '@lumino/polling';
|
|
4
|
-
import { COMPLETION_SYSTEM_PROMPT } from '
|
|
4
|
+
import { COMPLETION_SYSTEM_PROMPT } from '../../provider';
|
|
5
5
|
/**
|
|
6
6
|
* The Mistral API has a rate limit of 1 request per second
|
|
7
7
|
*/
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: "\n<i class=\"fas fa-exclamation-triangle\"></i> This extension is still very much experimental. It is not an official MistralAI extension.\n\n1. Go to <https://console.mistral.ai/api-keys/> and create an API key.\n\n <img src=\"https://raw.githubusercontent.com/jupyterlite/ai/refs/heads/main/img/1-api-key.png\" alt=\"Screenshot showing how to create an API key\" width=\"500px\">\n\n2. Open the JupyterLab settings and go to the **Ai providers** section to select the `MistralAI`\n provider and the API key (required).\n\n <img src=\"https://raw.githubusercontent.com/jupyterlite/ai/refs/heads/main/img/2-jupyterlab-settings.png\" alt=\"Screenshot showing how to add the API key to the settings\" width=\"500px\">\n\n3. Open the chat, or use the inline completer\n\n <img src=\"https://raw.githubusercontent.com/jupyterlite/ai/refs/heads/main/img/3-usage.png\" alt=\"Screenshot showing how to use the chat\" width=\"500px\">\n";
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default `
|
|
2
|
+
<i class="fas fa-exclamation-triangle"></i> This extension is still very much experimental. It is not an official MistralAI extension.
|
|
3
|
+
|
|
4
|
+
1. Go to <https://console.mistral.ai/api-keys/> and create an API key.
|
|
5
|
+
|
|
6
|
+
<img src="https://raw.githubusercontent.com/jupyterlite/ai/refs/heads/main/img/1-api-key.png" alt="Screenshot showing how to create an API key" width="500px">
|
|
7
|
+
|
|
8
|
+
2. Open the JupyterLab settings and go to the **Ai providers** section to select the \`MistralAI\`
|
|
9
|
+
provider and the API key (required).
|
|
10
|
+
|
|
11
|
+
<img src="https://raw.githubusercontent.com/jupyterlite/ai/refs/heads/main/img/2-jupyterlab-settings.png" alt="Screenshot showing how to add the API key to the settings" width="500px">
|
|
12
|
+
|
|
13
|
+
3. Open the chat, or use the inline completer
|
|
14
|
+
|
|
15
|
+
<img src="https://raw.githubusercontent.com/jupyterlite/ai/refs/heads/main/img/3-usage.png" alt="Screenshot showing how to use the chat" width="500px">
|
|
16
|
+
`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CompletionHandler, IInlineCompletionContext } from '@jupyterlab/completer';
|
|
2
2
|
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
3
|
-
import { BaseCompleter, IBaseCompleter } from '
|
|
3
|
+
import { BaseCompleter, IBaseCompleter } from '../../base-completer';
|
|
4
4
|
export declare class OpenAICompleter implements IBaseCompleter {
|
|
5
5
|
constructor(options: BaseCompleter.IOptions);
|
|
6
6
|
get provider(): BaseChatModel;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AIMessage, SystemMessage } from '@langchain/core/messages';
|
|
2
2
|
import { ChatOpenAI } from '@langchain/openai';
|
|
3
|
-
import { COMPLETION_SYSTEM_PROMPT } from '
|
|
3
|
+
import { COMPLETION_SYSTEM_PROMPT } from '../../provider';
|
|
4
4
|
export class OpenAICompleter {
|
|
5
5
|
constructor(options) {
|
|
6
6
|
this._prompt = COMPLETION_SYSTEM_PROMPT;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ChatAnthropic } from '@langchain/anthropic';
|
|
2
|
+
import { ChromeAI } from '@langchain/community/experimental/llms/chrome_ai';
|
|
3
|
+
import { ChatMistralAI } from '@langchain/mistralai';
|
|
4
|
+
import { ChatOpenAI } from '@langchain/openai';
|
|
5
|
+
import { IAIProviderRegistry } from '../tokens';
|
|
6
|
+
// Import completers
|
|
7
|
+
import { AnthropicCompleter } from './Anthropic/completer';
|
|
8
|
+
import { ChromeCompleter } from './ChromeAI/completer';
|
|
9
|
+
import { CodestralCompleter } from './MistralAI/completer';
|
|
10
|
+
import { OpenAICompleter } from './OpenAI/completer';
|
|
11
|
+
// Import Settings
|
|
12
|
+
import AnthropicSettings from './Anthropic/settings-schema.json';
|
|
13
|
+
import ChromeAISettings from './ChromeAI/settings-schema.json';
|
|
14
|
+
import MistralAISettings from './MistralAI/settings-schema.json';
|
|
15
|
+
import OpenAISettings from './OpenAI/settings-schema.json';
|
|
16
|
+
// Import instructions
|
|
17
|
+
import ChromeAIInstructions from './ChromeAI/instructions';
|
|
18
|
+
import MistralAIInstructions from './MistralAI/instructions';
|
|
19
|
+
// Build the AIProvider list
|
|
20
|
+
const AIProviders = [
|
|
21
|
+
{
|
|
22
|
+
name: 'Anthropic',
|
|
23
|
+
chatModel: ChatAnthropic,
|
|
24
|
+
completer: AnthropicCompleter,
|
|
25
|
+
settingsSchema: AnthropicSettings,
|
|
26
|
+
errorMessage: (error) => error.error.error.message
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'ChromeAI',
|
|
30
|
+
// TODO: fix
|
|
31
|
+
// @ts-expect-error: missing properties
|
|
32
|
+
chatModel: ChromeAI,
|
|
33
|
+
completer: ChromeCompleter,
|
|
34
|
+
instructions: ChromeAIInstructions,
|
|
35
|
+
settingsSchema: ChromeAISettings
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'MistralAI',
|
|
39
|
+
chatModel: ChatMistralAI,
|
|
40
|
+
completer: CodestralCompleter,
|
|
41
|
+
instructions: MistralAIInstructions,
|
|
42
|
+
settingsSchema: MistralAISettings
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'OpenAI',
|
|
46
|
+
chatModel: ChatOpenAI,
|
|
47
|
+
completer: OpenAICompleter,
|
|
48
|
+
settingsSchema: OpenAISettings
|
|
49
|
+
}
|
|
50
|
+
];
|
|
51
|
+
export const defaultProviderPlugins = AIProviders.map(provider => {
|
|
52
|
+
return {
|
|
53
|
+
id: `@jupyterlite/ai:${provider.name}`,
|
|
54
|
+
autoStart: true,
|
|
55
|
+
requires: [IAIProviderRegistry],
|
|
56
|
+
activate: (app, registry) => {
|
|
57
|
+
registry.add(provider);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
});
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IChatCommandRegistry } from '@jupyter/chat';
|
|
2
2
|
import { JupyterFrontEndPlugin } from '@jupyterlab/application';
|
|
3
|
-
import {
|
|
4
|
-
declare const _default: (JupyterFrontEndPlugin<void> | JupyterFrontEndPlugin<
|
|
3
|
+
import { IAIProviderRegistry } from './tokens';
|
|
4
|
+
declare const _default: (JupyterFrontEndPlugin<void> | JupyterFrontEndPlugin<IChatCommandRegistry> | JupyterFrontEndPlugin<IAIProviderRegistry>)[];
|
|
5
5
|
export default _default;
|
package/lib/index.js
CHANGED
|
@@ -1,46 +1,35 @@
|
|
|
1
|
-
import { ActiveCellManager,
|
|
1
|
+
import { ActiveCellManager, buildChatSidebar, buildErrorWidget, ChatCommandRegistry, IChatCommandRegistry } from '@jupyter/chat';
|
|
2
2
|
import { IThemeManager } from '@jupyterlab/apputils';
|
|
3
3
|
import { ICompletionProviderManager } from '@jupyterlab/completer';
|
|
4
4
|
import { INotebookTracker } from '@jupyterlab/notebook';
|
|
5
5
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
6
6
|
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
7
|
+
import { IFormRendererRegistry } from '@jupyterlab/ui-components';
|
|
8
|
+
import { ISecretsManager } from 'jupyter-secrets-manager';
|
|
7
9
|
import { ChatHandler } from './chat-handler';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
10
|
+
import { CompletionProvider } from './completion-provider';
|
|
11
|
+
import { defaultProviderPlugins } from './default-providers';
|
|
12
|
+
import { AIProviderRegistry } from './provider';
|
|
13
|
+
import { aiSettingsRenderer } from './settings/panel';
|
|
14
|
+
import { IAIProviderRegistry } from './tokens';
|
|
15
|
+
const chatCommandRegistryPlugin = {
|
|
13
16
|
id: '@jupyterlite/ai:autocompletion-registry',
|
|
14
17
|
description: 'Autocompletion registry',
|
|
15
18
|
autoStart: true,
|
|
16
|
-
provides:
|
|
19
|
+
provides: IChatCommandRegistry,
|
|
17
20
|
activate: () => {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
opener: '/',
|
|
22
|
-
commands: options.map(option => {
|
|
23
|
-
return {
|
|
24
|
-
id: option.slice(1),
|
|
25
|
-
label: option,
|
|
26
|
-
description: 'Clear the chat window'
|
|
27
|
-
};
|
|
28
|
-
}),
|
|
29
|
-
props: {
|
|
30
|
-
renderOption: renderSlashCommandOption
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
autocompletionRegistry.add('jupyterlite-ai', autocompletionCommands);
|
|
34
|
-
return autocompletionRegistry;
|
|
21
|
+
const registry = new ChatCommandRegistry();
|
|
22
|
+
registry.addProvider(new ChatHandler.ClearCommandProvider());
|
|
23
|
+
return registry;
|
|
35
24
|
}
|
|
36
25
|
};
|
|
37
26
|
const chatPlugin = {
|
|
38
27
|
id: '@jupyterlite/ai:chat',
|
|
39
28
|
description: 'LLM chat extension',
|
|
40
29
|
autoStart: true,
|
|
41
|
-
requires: [
|
|
30
|
+
requires: [IAIProviderRegistry, IRenderMimeRegistry, IChatCommandRegistry],
|
|
42
31
|
optional: [INotebookTracker, ISettingRegistry, IThemeManager],
|
|
43
|
-
activate: async (app,
|
|
32
|
+
activate: async (app, providerRegistry, rmRegistry, chatCommandRegistry, notebookTracker, settingsRegistry, themeManager) => {
|
|
44
33
|
let activeCellManager = null;
|
|
45
34
|
if (notebookTracker) {
|
|
46
35
|
activeCellManager = new ActiveCellManager({
|
|
@@ -49,8 +38,8 @@ const chatPlugin = {
|
|
|
49
38
|
});
|
|
50
39
|
}
|
|
51
40
|
const chatHandler = new ChatHandler({
|
|
52
|
-
|
|
53
|
-
activeCellManager
|
|
41
|
+
providerRegistry,
|
|
42
|
+
activeCellManager
|
|
54
43
|
});
|
|
55
44
|
let sendWithShiftEnter = false;
|
|
56
45
|
let enableCodeToolbar = true;
|
|
@@ -82,7 +71,7 @@ const chatPlugin = {
|
|
|
82
71
|
model: chatHandler,
|
|
83
72
|
themeManager,
|
|
84
73
|
rmRegistry,
|
|
85
|
-
|
|
74
|
+
chatCommandRegistry
|
|
86
75
|
});
|
|
87
76
|
chatWidget.title.caption = 'Jupyterlite AI Chat';
|
|
88
77
|
}
|
|
@@ -93,53 +82,51 @@ const chatPlugin = {
|
|
|
93
82
|
console.log('Chat extension initialized');
|
|
94
83
|
}
|
|
95
84
|
};
|
|
96
|
-
const
|
|
97
|
-
id: '@jupyterlite/ai:
|
|
85
|
+
const completerPlugin = {
|
|
86
|
+
id: '@jupyterlite/ai:completer',
|
|
98
87
|
autoStart: true,
|
|
99
|
-
requires: [
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
completionProviderManager: manager,
|
|
88
|
+
requires: [IAIProviderRegistry, ICompletionProviderManager],
|
|
89
|
+
activate: (app, providerRegistry, manager) => {
|
|
90
|
+
const completer = new CompletionProvider({
|
|
91
|
+
providerRegistry,
|
|
104
92
|
requestCompletion: () => app.commands.execute('inline-completer:invoke')
|
|
105
93
|
});
|
|
106
|
-
|
|
94
|
+
manager.registerInlineProvider(completer);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const providerRegistryPlugin = {
|
|
98
|
+
id: '@jupyterlite/ai:provider-registry',
|
|
99
|
+
autoStart: true,
|
|
100
|
+
requires: [IFormRendererRegistry, ISettingRegistry],
|
|
101
|
+
optional: [IRenderMimeRegistry, ISecretsManager],
|
|
102
|
+
provides: IAIProviderRegistry,
|
|
103
|
+
activate: (app, editorRegistry, settingRegistry, rmRegistry, secretsManager) => {
|
|
104
|
+
const providerRegistry = new AIProviderRegistry();
|
|
105
|
+
editorRegistry.addRenderer('@jupyterlite/ai:provider-registry.AIprovider', aiSettingsRenderer({ providerRegistry, rmRegistry, secretsManager }));
|
|
107
106
|
settingRegistry
|
|
108
|
-
.load(
|
|
107
|
+
.load(providerRegistryPlugin.id)
|
|
109
108
|
.then(settings => {
|
|
110
109
|
const updateProvider = () => {
|
|
111
|
-
|
|
112
|
-
if (provider !== currentProvider) {
|
|
113
|
-
// Update the settings panel.
|
|
114
|
-
currentProvider = provider;
|
|
115
|
-
const settingsProperties = settings.schema.properties;
|
|
116
|
-
if (settingsProperties) {
|
|
117
|
-
const schemaKeys = Object.keys(settingsProperties);
|
|
118
|
-
schemaKeys.forEach(key => {
|
|
119
|
-
var _a;
|
|
120
|
-
if (key !== 'provider') {
|
|
121
|
-
(_a = settings.schema.properties) === null || _a === void 0 ? true : delete _a[key];
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
const properties = getSettings(provider);
|
|
125
|
-
if (properties === null) {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
Object.entries(properties).forEach(([name, value], index) => {
|
|
129
|
-
settingsProperties[name] = value;
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
110
|
+
var _a;
|
|
133
111
|
// Update the settings to the AI providers.
|
|
134
|
-
|
|
112
|
+
const providerSettings = ((_a = settings.get('AIprovider').composite) !== null && _a !== void 0 ? _a : {
|
|
113
|
+
provider: 'None'
|
|
114
|
+
});
|
|
115
|
+
providerRegistry.setProvider(providerSettings.provider, providerSettings);
|
|
135
116
|
};
|
|
136
117
|
settings.changed.connect(() => updateProvider());
|
|
137
118
|
updateProvider();
|
|
138
119
|
})
|
|
139
120
|
.catch(reason => {
|
|
140
|
-
console.error(`Failed to load settings for ${
|
|
121
|
+
console.error(`Failed to load settings for ${providerRegistryPlugin.id}`, reason);
|
|
141
122
|
});
|
|
142
|
-
return
|
|
123
|
+
return providerRegistry;
|
|
143
124
|
}
|
|
144
125
|
};
|
|
145
|
-
export default [
|
|
126
|
+
export default [
|
|
127
|
+
providerRegistryPlugin,
|
|
128
|
+
chatCommandRegistryPlugin,
|
|
129
|
+
chatPlugin,
|
|
130
|
+
completerPlugin,
|
|
131
|
+
...defaultProviderPlugins
|
|
132
|
+
];
|