@jupyterlite/ai 0.6.2 → 0.8.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 +1 -1
- package/lib/base-completer.d.ts +22 -5
- package/lib/base-completer.js +14 -1
- package/lib/chat-handler.d.ts +23 -11
- package/lib/chat-handler.js +66 -45
- package/lib/completion-provider.d.ts +2 -2
- package/lib/completion-provider.js +5 -4
- package/lib/components/stop-button.d.ts +0 -1
- package/lib/default-prompts.d.ts +2 -0
- package/lib/default-prompts.js +31 -0
- package/lib/default-providers/Anthropic/completer.d.ts +4 -11
- package/lib/default-providers/Anthropic/completer.js +5 -16
- package/lib/default-providers/ChromeAI/completer.d.ts +4 -11
- package/lib/default-providers/ChromeAI/completer.js +5 -16
- package/lib/default-providers/ChromeAI/instructions.d.ts +4 -0
- package/lib/default-providers/ChromeAI/instructions.js +18 -0
- package/lib/default-providers/ChromeAI/settings-schema.json +0 -3
- package/lib/default-providers/Gemini/completer.d.ts +12 -0
- package/lib/default-providers/Gemini/completer.js +48 -0
- package/lib/default-providers/Gemini/instructions.d.ts +2 -0
- package/lib/default-providers/Gemini/instructions.js +9 -0
- package/lib/default-providers/Gemini/settings-schema.json +64 -0
- package/lib/default-providers/MistralAI/completer.d.ts +10 -13
- package/lib/default-providers/MistralAI/completer.js +42 -52
- package/lib/default-providers/MistralAI/instructions.d.ts +1 -1
- package/lib/default-providers/MistralAI/instructions.js +2 -0
- package/lib/default-providers/Ollama/completer.d.ts +12 -0
- package/lib/default-providers/Ollama/completer.js +43 -0
- package/lib/default-providers/Ollama/instructions.d.ts +2 -0
- package/lib/default-providers/Ollama/instructions.js +70 -0
- package/lib/default-providers/Ollama/settings-schema.json +143 -0
- package/lib/default-providers/OpenAI/completer.d.ts +4 -11
- package/lib/default-providers/OpenAI/completer.js +8 -16
- package/lib/default-providers/OpenAI/settings-schema.json +88 -128
- package/lib/default-providers/WebLLM/completer.d.ts +21 -0
- package/lib/default-providers/WebLLM/completer.js +127 -0
- package/lib/default-providers/WebLLM/instructions.d.ts +6 -0
- package/lib/default-providers/WebLLM/instructions.js +32 -0
- package/lib/default-providers/WebLLM/settings-schema.json +19 -0
- package/lib/default-providers/index.js +127 -8
- package/lib/index.d.ts +3 -2
- package/lib/index.js +80 -36
- package/lib/provider.d.ts +48 -22
- package/lib/provider.js +254 -101
- package/lib/settings/index.d.ts +1 -1
- package/lib/settings/index.js +1 -1
- package/lib/settings/panel.d.ts +151 -14
- package/lib/settings/panel.js +334 -145
- package/lib/settings/textarea.d.ts +2 -0
- package/lib/settings/textarea.js +18 -0
- package/lib/tokens.d.ts +45 -22
- package/lib/tokens.js +2 -1
- package/lib/types/ai-model.d.ts +24 -0
- package/lib/types/ai-model.js +5 -0
- package/package.json +19 -15
- package/schema/chat.json +1 -1
- package/schema/provider-registry.json +8 -8
- package/schema/system-prompts.json +22 -0
- package/src/base-completer.ts +38 -6
- package/src/chat-handler.ts +62 -31
- package/src/completion-provider.ts +3 -3
- package/src/default-prompts.ts +33 -0
- package/src/default-providers/Anthropic/completer.ts +5 -21
- package/src/default-providers/ChromeAI/completer.ts +5 -21
- package/src/default-providers/ChromeAI/instructions.ts +21 -0
- package/src/default-providers/Gemini/completer.ts +61 -0
- package/src/default-providers/Gemini/instructions.ts +9 -0
- package/src/default-providers/MistralAI/completer.ts +47 -65
- package/src/default-providers/MistralAI/instructions.ts +2 -0
- package/src/default-providers/Ollama/completer.ts +54 -0
- package/src/default-providers/Ollama/instructions.ts +70 -0
- package/src/default-providers/OpenAI/completer.ts +8 -21
- package/src/default-providers/WebLLM/completer.ts +151 -0
- package/src/default-providers/WebLLM/instructions.ts +33 -0
- package/src/default-providers/index.ts +158 -18
- package/src/index.ts +108 -40
- package/src/provider.ts +300 -109
- package/src/settings/index.ts +1 -1
- package/src/settings/panel.tsx +463 -101
- package/src/settings/textarea.tsx +33 -0
- package/src/tokens.ts +49 -24
- package/src/types/ai-model.ts +37 -0
- package/src/types/service-worker.d.ts +6 -0
- package/style/base.css +34 -0
- package/lib/settings/settings-connector.d.ts +0 -31
- package/lib/settings/settings-connector.js +0 -61
- package/src/settings/settings-connector.ts +0 -88
package/lib/tokens.d.ts
CHANGED
|
@@ -3,13 +3,16 @@ import { ReadonlyPartialJSONObject, Token } from '@lumino/coreutils';
|
|
|
3
3
|
import { ISignal } from '@lumino/signaling';
|
|
4
4
|
import { JSONSchema7 } from 'json-schema';
|
|
5
5
|
import { IBaseCompleter } from './base-completer';
|
|
6
|
+
import { AIChatModel, AICompleter } from './types/ai-model';
|
|
6
7
|
export declare const PLUGIN_IDS: {
|
|
7
8
|
chat: string;
|
|
8
9
|
chatCommandRegistry: string;
|
|
9
10
|
completer: string;
|
|
10
11
|
providerRegistry: string;
|
|
11
12
|
settingsConnector: string;
|
|
13
|
+
systemPrompts: string;
|
|
12
14
|
};
|
|
15
|
+
export type ModelRole = 'chat' | 'completer';
|
|
13
16
|
export interface IDict<T = any> {
|
|
14
17
|
[key: string]: T;
|
|
15
18
|
}
|
|
@@ -27,7 +30,7 @@ export interface IAIProvider {
|
|
|
27
30
|
/**
|
|
28
31
|
* The chat model class to use.
|
|
29
32
|
*/
|
|
30
|
-
|
|
33
|
+
chat?: IType<BaseChatModel>;
|
|
31
34
|
/**
|
|
32
35
|
* The completer class to use.
|
|
33
36
|
*/
|
|
@@ -46,6 +49,20 @@ export interface IAIProvider {
|
|
|
46
49
|
* Default to `(error) => error.message`.
|
|
47
50
|
*/
|
|
48
51
|
errorMessage?: (error: any) => string;
|
|
52
|
+
/**
|
|
53
|
+
* Compatibility check function, to determine if the provider is compatible with the
|
|
54
|
+
* current environment.
|
|
55
|
+
*/
|
|
56
|
+
compatibilityCheck?: () => Promise<string | null>;
|
|
57
|
+
/**
|
|
58
|
+
* Whether to expose or not the chat model.
|
|
59
|
+
*
|
|
60
|
+
* ### CAUTION
|
|
61
|
+
* This flag will expose the whole chat model API, which may contain private keys.
|
|
62
|
+
* Be sure to use it with a model that does not expose sensitive information in the
|
|
63
|
+
* API.
|
|
64
|
+
*/
|
|
65
|
+
exposeChatModel?: boolean;
|
|
49
66
|
}
|
|
50
67
|
/**
|
|
51
68
|
* The provider registry interface.
|
|
@@ -62,15 +79,23 @@ export interface IAIProviderRegistry {
|
|
|
62
79
|
/**
|
|
63
80
|
* Get the current provider name.
|
|
64
81
|
*/
|
|
65
|
-
currentName: string;
|
|
82
|
+
currentName(role: ModelRole): string;
|
|
66
83
|
/**
|
|
67
84
|
* Get the current completer of the completion provider.
|
|
68
85
|
*/
|
|
69
|
-
currentCompleter:
|
|
86
|
+
currentCompleter: AICompleter | null;
|
|
87
|
+
/**
|
|
88
|
+
* Getter/setter for the completer system prompt.
|
|
89
|
+
*/
|
|
90
|
+
completerSystemPrompt: string;
|
|
70
91
|
/**
|
|
71
92
|
* Get the current llm chat model.
|
|
72
93
|
*/
|
|
73
|
-
currentChatModel:
|
|
94
|
+
currentChatModel: AIChatModel | null;
|
|
95
|
+
/**
|
|
96
|
+
* Getter/setter for the chat system prompt.
|
|
97
|
+
*/
|
|
98
|
+
chatSystemPrompt: string;
|
|
74
99
|
/**
|
|
75
100
|
* Get the settings schema of a given provider.
|
|
76
101
|
*/
|
|
@@ -79,21 +104,32 @@ export interface IAIProviderRegistry {
|
|
|
79
104
|
* Get the instructions of a given provider.
|
|
80
105
|
*/
|
|
81
106
|
getInstructions(provider: string): string | undefined;
|
|
107
|
+
/**
|
|
108
|
+
* Get the compatibility check function of a given provider.
|
|
109
|
+
*/
|
|
110
|
+
getCompatibilityCheck(provider: string): (() => Promise<string | null>) | undefined;
|
|
82
111
|
/**
|
|
83
112
|
* Format an error message from the current provider.
|
|
84
113
|
*/
|
|
85
114
|
formatErrorMessage(error: any): string;
|
|
86
115
|
/**
|
|
87
|
-
* Set the
|
|
88
|
-
* Creates the
|
|
116
|
+
* Set the completer provider.
|
|
117
|
+
* Creates the provider if the name has changed, otherwise only updates its config.
|
|
89
118
|
*
|
|
90
|
-
* @param options -
|
|
119
|
+
* @param options - An object with the name and the settings of the provider to use.
|
|
91
120
|
*/
|
|
92
|
-
|
|
121
|
+
setCompleterProvider(settings: ReadonlyPartialJSONObject): void;
|
|
122
|
+
/**
|
|
123
|
+
* Set the chat provider.
|
|
124
|
+
* Creates the provider if the name has changed, otherwise only updates its config.
|
|
125
|
+
*
|
|
126
|
+
* @param options - An object with the name and the settings of the provider to use.
|
|
127
|
+
*/
|
|
128
|
+
setChatProvider(settings: ReadonlyPartialJSONObject): void;
|
|
93
129
|
/**
|
|
94
130
|
* A signal emitting when the provider or its settings has changed.
|
|
95
131
|
*/
|
|
96
|
-
readonly providerChanged: ISignal<IAIProviderRegistry,
|
|
132
|
+
readonly providerChanged: ISignal<IAIProviderRegistry, ModelRole>;
|
|
97
133
|
/**
|
|
98
134
|
* Get the current chat error;
|
|
99
135
|
*/
|
|
@@ -103,19 +139,6 @@ export interface IAIProviderRegistry {
|
|
|
103
139
|
*/
|
|
104
140
|
readonly completerError: string;
|
|
105
141
|
}
|
|
106
|
-
/**
|
|
107
|
-
* The set provider options.
|
|
108
|
-
*/
|
|
109
|
-
export interface ISetProviderOptions {
|
|
110
|
-
/**
|
|
111
|
-
* The name of the provider.
|
|
112
|
-
*/
|
|
113
|
-
name: string;
|
|
114
|
-
/**
|
|
115
|
-
* The settings of the provider.
|
|
116
|
-
*/
|
|
117
|
-
settings: ReadonlyPartialJSONObject;
|
|
118
|
-
}
|
|
119
142
|
/**
|
|
120
143
|
* The provider registry token.
|
|
121
144
|
*/
|
package/lib/tokens.js
CHANGED
|
@@ -4,7 +4,8 @@ export const PLUGIN_IDS = {
|
|
|
4
4
|
chatCommandRegistry: '@jupyterlite/ai:autocompletion-registry',
|
|
5
5
|
completer: '@jupyterlite/ai:completer',
|
|
6
6
|
providerRegistry: '@jupyterlite/ai:provider-registry',
|
|
7
|
-
settingsConnector: '@jupyterlite/ai:settings-connector'
|
|
7
|
+
settingsConnector: '@jupyterlite/ai:settings-connector',
|
|
8
|
+
systemPrompts: '@jupyterlite/ai:system-prompts'
|
|
8
9
|
};
|
|
9
10
|
/**
|
|
10
11
|
* The provider registry token.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CompletionHandler, IInlineCompletionContext } from '@jupyterlab/completer';
|
|
2
|
+
import { IterableReadableStream } from '@langchain/core/utils/stream';
|
|
3
|
+
/**
|
|
4
|
+
* The reduced AI chat model interface.
|
|
5
|
+
*/
|
|
6
|
+
export type AIChatModel = {
|
|
7
|
+
/**
|
|
8
|
+
* The stream function of the chat model.
|
|
9
|
+
*/
|
|
10
|
+
stream: (input: any, options?: any) => Promise<IterableReadableStream<any>>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* The reduced AI completer interface.
|
|
14
|
+
*/
|
|
15
|
+
export type AICompleter = {
|
|
16
|
+
/**
|
|
17
|
+
* The fetch function of the completer.
|
|
18
|
+
*/
|
|
19
|
+
fetch: (request: CompletionHandler.IRequest, context: IInlineCompletionContext) => Promise<any>;
|
|
20
|
+
/**
|
|
21
|
+
* The optional request completion function of the completer.
|
|
22
|
+
*/
|
|
23
|
+
requestCompletion?: () => void;
|
|
24
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupyterlite/ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "AI code completions and chat for JupyterLite",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "jlpm build:lib && jlpm build:labextension:dev",
|
|
31
31
|
"build:dev": "jlpm build:lib && jlpm build:labextension:dev",
|
|
32
|
-
"build:prod": "jlpm
|
|
32
|
+
"build:prod": "jlpm clean && jlpm build:lib:prod && jlpm build:labextension",
|
|
33
33
|
"build:labextension": "jupyter labextension build .",
|
|
34
34
|
"build:labextension:dev": "jupyter labextension build --development True .",
|
|
35
35
|
"build:lib": "tsc --sourceMap",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"watch:labextension": "jupyter labextension watch ."
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@jupyter/chat": "^0.
|
|
59
|
+
"@jupyter/chat": "^0.14.0",
|
|
60
60
|
"@jupyterlab/application": "^4.4.0",
|
|
61
61
|
"@jupyterlab/apputils": "^4.5.0",
|
|
62
62
|
"@jupyterlab/completer": "^4.4.0",
|
|
@@ -65,32 +65,39 @@
|
|
|
65
65
|
"@jupyterlab/rendermime": "^4.4.0",
|
|
66
66
|
"@jupyterlab/settingregistry": "^4.4.0",
|
|
67
67
|
"@jupyterlab/ui-components": "^4.4.0",
|
|
68
|
-
"@langchain/anthropic": "^0.3.
|
|
69
|
-
"@langchain/community": "^0.3.
|
|
70
|
-
"@langchain/core": "^0.3.
|
|
71
|
-
"@langchain/
|
|
72
|
-
"@langchain/
|
|
68
|
+
"@langchain/anthropic": "^0.3.24",
|
|
69
|
+
"@langchain/community": "^0.3.48",
|
|
70
|
+
"@langchain/core": "^0.3.62",
|
|
71
|
+
"@langchain/google-genai": "^0.2.14",
|
|
72
|
+
"@langchain/mistralai": "^0.2.1",
|
|
73
|
+
"@langchain/ollama": "^0.2.3",
|
|
74
|
+
"@langchain/openai": "^0.5.16",
|
|
73
75
|
"@lumino/coreutils": "^2.1.2",
|
|
74
76
|
"@lumino/polling": "^2.1.2",
|
|
75
77
|
"@lumino/signaling": "^2.1.2",
|
|
78
|
+
"@mlc-ai/web-llm": "^0.2.79",
|
|
79
|
+
"@mlc-ai/web-runtime": "^0.18.0-dev2",
|
|
80
|
+
"@mlc-ai/web-tokenizers": "^0.1.6",
|
|
76
81
|
"@mui/icons-material": "^5.11.0",
|
|
77
82
|
"@mui/material": "^5.11.0",
|
|
78
83
|
"@rjsf/core": "^5.18.4",
|
|
79
84
|
"@rjsf/utils": "^5.18.4",
|
|
80
85
|
"@rjsf/validator-ajv8": "^5.18.4",
|
|
81
86
|
"json5": "^2.2.3",
|
|
82
|
-
"jupyter-secrets-manager": "^0.
|
|
87
|
+
"jupyter-secrets-manager": "^0.4.0",
|
|
83
88
|
"react": "^18.2.0",
|
|
84
89
|
"react-dom": "^18.2.0"
|
|
85
90
|
},
|
|
86
91
|
"devDependencies": {
|
|
87
92
|
"@jupyterlab/builder": "^4.4.0",
|
|
88
93
|
"@stylistic/eslint-plugin": "^3.0.1",
|
|
94
|
+
"@types/chrome": "^0.0.304",
|
|
89
95
|
"@types/json-schema": "^7.0.11",
|
|
90
96
|
"@types/react": "^18.0.26",
|
|
91
97
|
"@types/react-addons-linked-state-mixin": "^0.14.22",
|
|
92
98
|
"@typescript-eslint/eslint-plugin": "^6.1.0",
|
|
93
99
|
"@typescript-eslint/parser": "^6.1.0",
|
|
100
|
+
"@webgpu/types": "^0.1.54",
|
|
94
101
|
"css-loader": "^6.7.1",
|
|
95
102
|
"eslint": "^8.36.0",
|
|
96
103
|
"eslint-config-prettier": "^8.8.0",
|
|
@@ -105,8 +112,8 @@
|
|
|
105
112
|
"stylelint-config-standard": "^34.0.0",
|
|
106
113
|
"stylelint-csstree-validator": "^3.0.0",
|
|
107
114
|
"stylelint-prettier": "^4.0.0",
|
|
108
|
-
"ts-json-schema-generator": "^2.
|
|
109
|
-
"typescript": "~5.
|
|
115
|
+
"ts-json-schema-generator": "^2.4.0",
|
|
116
|
+
"typescript": "~5.8.3",
|
|
110
117
|
"yjs": "^13.5.0"
|
|
111
118
|
},
|
|
112
119
|
"sideEffects": [
|
|
@@ -120,9 +127,6 @@
|
|
|
120
127
|
"jupyterlab": {
|
|
121
128
|
"extension": true,
|
|
122
129
|
"outputDir": "jupyterlite_ai/labextension",
|
|
123
|
-
"schemaDir": "schema"
|
|
124
|
-
"disabledExtensions": [
|
|
125
|
-
"@jupyterlab/apputils-extension:settings-connector"
|
|
126
|
-
]
|
|
130
|
+
"schemaDir": "schema"
|
|
127
131
|
}
|
|
128
132
|
}
|
package/schema/chat.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"title": "AI
|
|
2
|
+
"title": "AI providers",
|
|
3
3
|
"description": "Provider registry settings",
|
|
4
4
|
"jupyter.lab.setting-icon": "@jupyterlite/ai:jupyternaut-lite",
|
|
5
|
-
"jupyter.lab.setting-icon-label": "JupyterLite AI
|
|
5
|
+
"jupyter.lab.setting-icon-label": "JupyterLite AI provider",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"properties": {
|
|
8
8
|
"UseSecretsManager": {
|
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
"description": "Whether to use or not the secrets manager. If not, secrets will be stored in the browser (local storage)",
|
|
12
12
|
"default": true
|
|
13
13
|
},
|
|
14
|
-
"
|
|
14
|
+
"UniqueProvider": {
|
|
15
15
|
"type": "boolean",
|
|
16
|
-
"title": "
|
|
17
|
-
"description": "Whether to
|
|
16
|
+
"title": "Use the same provider for chat and completer",
|
|
17
|
+
"description": "Whether to use only one provider for the chat and the completer.\nThis will overwrite all the settings for the completer, and copy the ones from the chat.",
|
|
18
18
|
"default": true
|
|
19
19
|
},
|
|
20
|
-
"
|
|
20
|
+
"AIproviders": {
|
|
21
21
|
"type": "object",
|
|
22
|
-
"title": "AI
|
|
23
|
-
"description": "The AI
|
|
22
|
+
"title": "AI providers",
|
|
23
|
+
"description": "The AI providers configuration",
|
|
24
24
|
"default": {},
|
|
25
25
|
"additionalProperties": true
|
|
26
26
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "AI system prompts",
|
|
3
|
+
"description": "System prompts",
|
|
4
|
+
"jupyter.lab.setting-icon": "@jupyterlite/ai:jupyternaut-lite",
|
|
5
|
+
"jupyter.lab.setting-icon-label": "JupyterLite AI Chat",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"chatSystemPrompt": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"title": "Chat message system prompt",
|
|
11
|
+
"description": "The system prompt for the chat messages",
|
|
12
|
+
"default": "You are Jupyternaut, a conversational assistant living in JupyterLab to help users.\nYou are not a language model, but rather an application built on a foundation model from $provider_name$.\nYou are talkative and you provide lots of specific details from the foundation model's context.\nYou may use Markdown to format your response.\nIf your response includes code, they must be enclosed in Markdown fenced code blocks (with triple backticks before and after).\nIf your response includes mathematical notation, they must be expressed in LaTeX markup and enclosed in LaTeX delimiters.\nAll dollar quantities (of USD) must be formatted in LaTeX, with the `$` symbol escaped by a single backslash `\\`.\n- Example prompt: `If I have \\\\$100 and spend \\\\$20, how much money do I have left?`\n- **Correct** response: `You have \\(\\$80\\) remaining.`\n- **Incorrect** response: `You have $80 remaining.`\nIf you do not know the answer to a question, answer truthfully by responding that you do not know.\nThe following is a friendly conversation between you and a human."
|
|
13
|
+
},
|
|
14
|
+
"completionSystemPrompt": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"title": "Completion system prompt",
|
|
17
|
+
"description": "The system prompt for the completion",
|
|
18
|
+
"default": "You are an application built to provide helpful code completion suggestions.\nYou should only produce code. Keep comments to minimum, use the programming language comment syntax. Produce clean code.\nThe code is written in JupyterLab, a data analysis and code development environment which can execute code extended with additional syntax for interactive features, such as magics.\nOnly give raw strings back, do not format the response using backticks.\nThe output should be a single string, and should only contain the code that will complete the give code passed as input, no explanation whatsoever. Do not include the prompt in the output, only the string that should be appended to the current input. Here is the code to complete:"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"additionalProperties": false
|
|
22
|
+
}
|
package/src/base-completer.ts
CHANGED
|
@@ -5,16 +5,14 @@ import {
|
|
|
5
5
|
import { BaseLanguageModel } from '@langchain/core/language_models/base';
|
|
6
6
|
import { ReadonlyPartialJSONObject } from '@lumino/coreutils';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* The LLM completer.
|
|
11
|
-
*/
|
|
12
|
-
completer: BaseLanguageModel;
|
|
8
|
+
import { DEFAULT_COMPLETION_SYSTEM_PROMPT } from './default-prompts';
|
|
9
|
+
import { IAIProviderRegistry } from './tokens';
|
|
13
10
|
|
|
11
|
+
export interface IBaseCompleter {
|
|
14
12
|
/**
|
|
15
13
|
* The completion prompt.
|
|
16
14
|
*/
|
|
17
|
-
|
|
15
|
+
readonly systemPrompt: string;
|
|
18
16
|
|
|
19
17
|
/**
|
|
20
18
|
* The function to fetch a new completion.
|
|
@@ -30,6 +28,33 @@ export interface IBaseCompleter {
|
|
|
30
28
|
): Promise<any>;
|
|
31
29
|
}
|
|
32
30
|
|
|
31
|
+
export abstract class BaseCompleter implements IBaseCompleter {
|
|
32
|
+
constructor(options: BaseCompleter.IOptions) {
|
|
33
|
+
this._providerRegistry = options.providerRegistry;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get the system prompt for the completion.
|
|
38
|
+
*/
|
|
39
|
+
get systemPrompt(): string {
|
|
40
|
+
return (
|
|
41
|
+
this._providerRegistry.completerSystemPrompt ??
|
|
42
|
+
DEFAULT_COMPLETION_SYSTEM_PROMPT
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The fetch request for the LLM completer.
|
|
48
|
+
*/
|
|
49
|
+
abstract fetch(
|
|
50
|
+
request: CompletionHandler.IRequest,
|
|
51
|
+
context: IInlineCompletionContext
|
|
52
|
+
): Promise<any>;
|
|
53
|
+
|
|
54
|
+
protected _providerRegistry: IAIProviderRegistry;
|
|
55
|
+
protected abstract _completer: BaseLanguageModel<any, any>;
|
|
56
|
+
}
|
|
57
|
+
|
|
33
58
|
/**
|
|
34
59
|
* The namespace for the base completer.
|
|
35
60
|
*/
|
|
@@ -38,6 +63,13 @@ export namespace BaseCompleter {
|
|
|
38
63
|
* The options for the constructor of a completer.
|
|
39
64
|
*/
|
|
40
65
|
export interface IOptions {
|
|
66
|
+
/**
|
|
67
|
+
* The provider registry.
|
|
68
|
+
*/
|
|
69
|
+
providerRegistry: IAIProviderRegistry;
|
|
70
|
+
/**
|
|
71
|
+
* The settings of the provider.
|
|
72
|
+
*/
|
|
41
73
|
settings: ReadonlyPartialJSONObject;
|
|
42
74
|
}
|
|
43
75
|
}
|
package/src/chat-handler.ts
CHANGED
|
@@ -5,14 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
ChatCommand,
|
|
8
|
-
|
|
8
|
+
AbstractChatContext,
|
|
9
|
+
AbstractChatModel,
|
|
9
10
|
IChatCommandProvider,
|
|
11
|
+
IChatContext,
|
|
10
12
|
IChatHistory,
|
|
11
13
|
IChatMessage,
|
|
14
|
+
IChatModel,
|
|
12
15
|
IInputModel,
|
|
13
16
|
INewMessage
|
|
14
17
|
} from '@jupyter/chat';
|
|
15
|
-
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
16
18
|
import {
|
|
17
19
|
AIMessage,
|
|
18
20
|
HumanMessage,
|
|
@@ -20,9 +22,11 @@ import {
|
|
|
20
22
|
SystemMessage
|
|
21
23
|
} from '@langchain/core/messages';
|
|
22
24
|
import { UUID } from '@lumino/coreutils';
|
|
23
|
-
|
|
24
|
-
import {
|
|
25
|
+
|
|
26
|
+
import { DEFAULT_CHAT_SYSTEM_PROMPT } from './default-prompts';
|
|
25
27
|
import { jupyternautLiteIcon } from './icons';
|
|
28
|
+
import { IAIProviderRegistry } from './tokens';
|
|
29
|
+
import { AIChatModel } from './types/ai-model';
|
|
26
30
|
|
|
27
31
|
/**
|
|
28
32
|
* The base64 encoded SVG string of the jupyternaut lite icon.
|
|
@@ -31,28 +35,34 @@ import { jupyternautLiteIcon } from './icons';
|
|
|
31
35
|
const AI_AVATAR_BASE64 = btoa(jupyternautLiteIcon.svgstr);
|
|
32
36
|
const AI_AVATAR = `data:image/svg+xml;base64,${AI_AVATAR_BASE64}`;
|
|
33
37
|
|
|
38
|
+
export const welcomeMessage = (providers: string[]) => `
|
|
39
|
+
#### Ask JupyterLite AI
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
The provider to use can be set in the <button data-commandLinker-command="settingeditor:open" data-commandLinker-args='{"query": "AI provider"}' href="#">settings editor</button>, by selecting it from
|
|
43
|
+
the <img src="${AI_AVATAR}" width="16" height="16"> _AI provider_ settings.
|
|
44
|
+
|
|
45
|
+
The current providers that are available are _${providers.sort().join('_, _')}_.
|
|
46
|
+
|
|
47
|
+
To clear the chat, you can use the \`/clear\` command from the chat input.
|
|
48
|
+
`;
|
|
49
|
+
|
|
34
50
|
export type ConnectionMessage = {
|
|
35
51
|
type: 'connection';
|
|
36
52
|
client_id: string;
|
|
37
53
|
};
|
|
38
54
|
|
|
39
|
-
export class ChatHandler extends
|
|
55
|
+
export class ChatHandler extends AbstractChatModel {
|
|
40
56
|
constructor(options: ChatHandler.IOptions) {
|
|
41
57
|
super(options);
|
|
42
58
|
this._providerRegistry = options.providerRegistry;
|
|
43
|
-
this._prompt = chatSystemPrompt({
|
|
44
|
-
provider_name: this._providerRegistry.currentName
|
|
45
|
-
});
|
|
46
59
|
|
|
47
60
|
this._providerRegistry.providerChanged.connect(() => {
|
|
48
61
|
this._errorMessage = this._providerRegistry.chatError;
|
|
49
|
-
this._prompt = chatSystemPrompt({
|
|
50
|
-
provider_name: this._providerRegistry.currentName
|
|
51
|
-
});
|
|
52
62
|
});
|
|
53
63
|
}
|
|
54
64
|
|
|
55
|
-
get provider():
|
|
65
|
+
get provider(): AIChatModel | null {
|
|
56
66
|
return this._providerRegistry.currentChatModel;
|
|
57
67
|
}
|
|
58
68
|
|
|
@@ -74,13 +84,12 @@ export class ChatHandler extends ChatModel {
|
|
|
74
84
|
}
|
|
75
85
|
|
|
76
86
|
/**
|
|
77
|
-
*
|
|
87
|
+
* Get/set the system prompt for the chat.
|
|
78
88
|
*/
|
|
79
|
-
get
|
|
80
|
-
return
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this._prompt = value;
|
|
89
|
+
get systemPrompt(): string {
|
|
90
|
+
return (
|
|
91
|
+
this._providerRegistry.chatSystemPrompt ?? DEFAULT_CHAT_SYSTEM_PROMPT
|
|
92
|
+
);
|
|
84
93
|
}
|
|
85
94
|
|
|
86
95
|
async sendMessage(message: INewMessage): Promise<boolean> {
|
|
@@ -96,7 +105,7 @@ export class ChatHandler extends ChatModel {
|
|
|
96
105
|
id: message.id,
|
|
97
106
|
body,
|
|
98
107
|
sender: { username: 'User' },
|
|
99
|
-
time:
|
|
108
|
+
time: Private.getTimestampMs(),
|
|
100
109
|
type: 'msg'
|
|
101
110
|
};
|
|
102
111
|
this.messageAdded(msg);
|
|
@@ -106,7 +115,7 @@ export class ChatHandler extends ChatModel {
|
|
|
106
115
|
id: UUID.uuid4(),
|
|
107
116
|
body: `**${this._errorMessage ? this._errorMessage : this._defaultErrorMessage}**`,
|
|
108
117
|
sender: { username: 'ERROR' },
|
|
109
|
-
time:
|
|
118
|
+
time: Private.getTimestampMs(),
|
|
110
119
|
type: 'msg'
|
|
111
120
|
};
|
|
112
121
|
this.messageAdded(errorMsg);
|
|
@@ -115,7 +124,7 @@ export class ChatHandler extends ChatModel {
|
|
|
115
124
|
|
|
116
125
|
this._history.messages.push(msg);
|
|
117
126
|
|
|
118
|
-
const messages = mergeMessageRuns([new SystemMessage(this.
|
|
127
|
+
const messages = mergeMessageRuns([new SystemMessage(this.systemPrompt)]);
|
|
119
128
|
messages.push(
|
|
120
129
|
...this._history.messages.map(msg => {
|
|
121
130
|
if (msg.sender.username === 'User') {
|
|
@@ -126,14 +135,14 @@ export class ChatHandler extends ChatModel {
|
|
|
126
135
|
);
|
|
127
136
|
|
|
128
137
|
const sender = { username: this._personaName, avatar_url: AI_AVATAR };
|
|
129
|
-
this.updateWriters([sender]);
|
|
138
|
+
this.updateWriters([{ user: sender }]);
|
|
130
139
|
|
|
131
140
|
// create an empty message to be filled by the AI provider
|
|
132
141
|
const botMsg: IChatMessage = {
|
|
133
142
|
id: UUID.uuid4(),
|
|
134
143
|
body: '',
|
|
135
144
|
sender,
|
|
136
|
-
time:
|
|
145
|
+
time: Private.getTimestampMs(),
|
|
137
146
|
type: 'msg'
|
|
138
147
|
};
|
|
139
148
|
|
|
@@ -157,7 +166,7 @@ export class ChatHandler extends ChatModel {
|
|
|
157
166
|
id: UUID.uuid4(),
|
|
158
167
|
body: `**${error}**`,
|
|
159
168
|
sender: { username: 'ERROR' },
|
|
160
|
-
time:
|
|
169
|
+
time: Private.getTimestampMs(),
|
|
161
170
|
type: 'msg'
|
|
162
171
|
};
|
|
163
172
|
this.messageAdded(errorMsg);
|
|
@@ -184,9 +193,12 @@ export class ChatHandler extends ChatModel {
|
|
|
184
193
|
this._controller?.abort();
|
|
185
194
|
}
|
|
186
195
|
|
|
196
|
+
createChatContext(): IChatContext {
|
|
197
|
+
return new ChatHandler.ChatContext({ model: this });
|
|
198
|
+
}
|
|
199
|
+
|
|
187
200
|
private _providerRegistry: IAIProviderRegistry;
|
|
188
201
|
private _personaName = 'AI';
|
|
189
|
-
private _prompt: string;
|
|
190
202
|
private _errorMessage: string = '';
|
|
191
203
|
private _history: IChatHistory = { messages: [] };
|
|
192
204
|
private _defaultErrorMessage = 'AI provider not configured';
|
|
@@ -194,10 +206,23 @@ export class ChatHandler extends ChatModel {
|
|
|
194
206
|
}
|
|
195
207
|
|
|
196
208
|
export namespace ChatHandler {
|
|
197
|
-
|
|
209
|
+
/**
|
|
210
|
+
* The options used to create a chat handler.
|
|
211
|
+
*/
|
|
212
|
+
export interface IOptions extends IChatModel.IOptions {
|
|
198
213
|
providerRegistry: IAIProviderRegistry;
|
|
199
214
|
}
|
|
200
215
|
|
|
216
|
+
/**
|
|
217
|
+
* The minimal chat context.
|
|
218
|
+
*/
|
|
219
|
+
export class ChatContext extends AbstractChatContext {
|
|
220
|
+
users = [];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* The chat command provider for the chat.
|
|
225
|
+
*/
|
|
201
226
|
export class ClearCommandProvider implements IChatCommandProvider {
|
|
202
227
|
public id: string = '@jupyterlite/ai:clear-commands';
|
|
203
228
|
private _slash_commands: ChatCommand[] = [
|
|
@@ -208,7 +233,7 @@ export namespace ChatHandler {
|
|
|
208
233
|
description: 'Clear the chat'
|
|
209
234
|
}
|
|
210
235
|
];
|
|
211
|
-
async
|
|
236
|
+
async listCommandCompletions(inputModel: IInputModel) {
|
|
212
237
|
const match = inputModel.currentWord?.match(/^\/\w*/)?.[0];
|
|
213
238
|
if (!match) {
|
|
214
239
|
return [];
|
|
@@ -220,12 +245,18 @@ export namespace ChatHandler {
|
|
|
220
245
|
return commands;
|
|
221
246
|
}
|
|
222
247
|
|
|
223
|
-
async
|
|
224
|
-
command: ChatCommand,
|
|
225
|
-
inputModel: IInputModel
|
|
226
|
-
): Promise<void> {
|
|
248
|
+
async onSubmit(inputModel: IInputModel): Promise<void> {
|
|
227
249
|
// no handling needed because `replaceWith` is set in each command.
|
|
228
250
|
return;
|
|
229
251
|
}
|
|
230
252
|
}
|
|
231
253
|
}
|
|
254
|
+
|
|
255
|
+
namespace Private {
|
|
256
|
+
/**
|
|
257
|
+
* Return the current timestamp in milliseconds.
|
|
258
|
+
*/
|
|
259
|
+
export function getTimestampMs(): number {
|
|
260
|
+
return Date.now() / 1000;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
IInlineCompletionProvider
|
|
5
5
|
} from '@jupyterlab/completer';
|
|
6
6
|
|
|
7
|
-
import { IBaseCompleter } from './base-completer';
|
|
8
7
|
import { IAIProviderRegistry } from './tokens';
|
|
8
|
+
import { AICompleter } from './types/ai-model';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* The generic completion provider to register to the completion provider manager.
|
|
@@ -28,13 +28,13 @@ export class CompletionProvider implements IInlineCompletionProvider {
|
|
|
28
28
|
* Get the current completer name.
|
|
29
29
|
*/
|
|
30
30
|
get name(): string {
|
|
31
|
-
return this._providerRegistry.currentName;
|
|
31
|
+
return this._providerRegistry.currentName('completer');
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Get the current completer.
|
|
36
36
|
*/
|
|
37
|
-
get completer():
|
|
37
|
+
get completer(): AICompleter | null {
|
|
38
38
|
return this._providerRegistry.currentCompleter;
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Jupyter Development Team.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_CHAT_SYSTEM_PROMPT = `
|
|
7
|
+
You are Jupyternaut, a conversational assistant living in JupyterLab to help users.
|
|
8
|
+
You are not a language model, but rather an application built on a foundation model from $provider_name$.
|
|
9
|
+
You are talkative and you provide lots of specific details from the foundation model's context.
|
|
10
|
+
You may use Markdown to format your response.
|
|
11
|
+
If your response includes code, they must be enclosed in Markdown fenced code blocks (with triple backticks before and after).
|
|
12
|
+
If your response includes mathematical notation, they must be expressed in LaTeX markup and enclosed in LaTeX delimiters.
|
|
13
|
+
All dollar quantities (of USD) must be formatted in LaTeX, with the \`$\` symbol escaped by a single backslash \`\\\`.
|
|
14
|
+
- Example prompt: \`If I have \\\\$100 and spend \\\\$20, how much money do I have left?\`
|
|
15
|
+
- **Correct** response: \`You have \\(\\$80\\) remaining.\`
|
|
16
|
+
- **Incorrect** response: \`You have $80 remaining.\`
|
|
17
|
+
If you do not know the answer to a question, answer truthfully by responding that you do not know.
|
|
18
|
+
The following is a friendly conversation between you and a human.
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
export const DEFAULT_COMPLETION_SYSTEM_PROMPT = `
|
|
22
|
+
You are an application built to provide helpful code completion suggestions.
|
|
23
|
+
You should only produce code. Keep comments to minimum, use the
|
|
24
|
+
programming language comment syntax. Produce clean code.
|
|
25
|
+
The code is written in JupyterLab, a data analysis and code development
|
|
26
|
+
environment which can execute code extended with additional syntax for
|
|
27
|
+
interactive features, such as magics.
|
|
28
|
+
Only give raw strings back, do not format the response using backticks.
|
|
29
|
+
The output should be a single string, and should only contain the code that will complete the
|
|
30
|
+
give code passed as input, no explanation whatsoever.
|
|
31
|
+
Do not include the prompt in the output, only the string that should be appended to the current input.
|
|
32
|
+
Here is the code to complete:
|
|
33
|
+
`;
|