@jupyterlite/ai 0.6.2 → 0.7.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.
Files changed (65) hide show
  1. package/README.md +1 -1
  2. package/lib/base-completer.d.ts +0 -5
  3. package/lib/chat-handler.d.ts +19 -5
  4. package/lib/chat-handler.js +47 -26
  5. package/lib/completion-provider.d.ts +2 -2
  6. package/lib/completion-provider.js +4 -3
  7. package/lib/components/stop-button.d.ts +0 -1
  8. package/lib/default-providers/Anthropic/completer.d.ts +0 -2
  9. package/lib/default-providers/Anthropic/completer.js +2 -4
  10. package/lib/default-providers/ChromeAI/completer.d.ts +0 -2
  11. package/lib/default-providers/ChromeAI/completer.js +2 -4
  12. package/lib/default-providers/ChromeAI/instructions.d.ts +4 -0
  13. package/lib/default-providers/ChromeAI/instructions.js +18 -0
  14. package/lib/default-providers/MistralAI/completer.d.ts +0 -2
  15. package/lib/default-providers/MistralAI/completer.js +3 -4
  16. package/lib/default-providers/Ollama/completer.d.ts +17 -0
  17. package/lib/default-providers/Ollama/completer.js +49 -0
  18. package/lib/default-providers/Ollama/instructions.d.ts +2 -0
  19. package/lib/default-providers/Ollama/instructions.js +70 -0
  20. package/lib/default-providers/Ollama/settings-schema.json +146 -0
  21. package/lib/default-providers/OpenAI/completer.d.ts +0 -2
  22. package/lib/default-providers/OpenAI/completer.js +2 -4
  23. package/lib/default-providers/WebLLM/completer.d.ts +27 -0
  24. package/lib/default-providers/WebLLM/completer.js +136 -0
  25. package/lib/default-providers/WebLLM/instructions.d.ts +6 -0
  26. package/lib/default-providers/WebLLM/instructions.js +32 -0
  27. package/lib/default-providers/WebLLM/settings-schema.json +21 -0
  28. package/lib/default-providers/index.js +119 -4
  29. package/lib/index.d.ts +2 -2
  30. package/lib/index.js +16 -26
  31. package/lib/provider.d.ts +11 -13
  32. package/lib/provider.js +120 -52
  33. package/lib/settings/index.d.ts +0 -1
  34. package/lib/settings/index.js +0 -1
  35. package/lib/settings/panel.d.ts +37 -8
  36. package/lib/settings/panel.js +225 -131
  37. package/lib/tokens.d.ts +21 -2
  38. package/lib/types/ai-model.d.ts +24 -0
  39. package/lib/types/ai-model.js +5 -0
  40. package/package.json +14 -11
  41. package/schema/provider-registry.json +0 -6
  42. package/src/base-completer.ts +0 -6
  43. package/src/chat-handler.ts +40 -7
  44. package/src/completion-provider.ts +2 -2
  45. package/src/default-providers/Anthropic/completer.ts +0 -5
  46. package/src/default-providers/ChromeAI/completer.ts +0 -5
  47. package/src/default-providers/ChromeAI/instructions.ts +21 -0
  48. package/src/default-providers/MistralAI/completer.ts +0 -5
  49. package/src/default-providers/Ollama/completer.ts +62 -0
  50. package/src/default-providers/Ollama/instructions.ts +70 -0
  51. package/src/default-providers/OpenAI/completer.ts +0 -5
  52. package/src/default-providers/WebLLM/completer.ts +162 -0
  53. package/src/default-providers/WebLLM/instructions.ts +33 -0
  54. package/src/default-providers/index.ts +151 -14
  55. package/src/index.ts +17 -29
  56. package/src/provider.ts +132 -45
  57. package/src/settings/index.ts +0 -1
  58. package/src/settings/panel.tsx +207 -73
  59. package/src/tokens.ts +23 -2
  60. package/src/types/ai-model.ts +37 -0
  61. package/src/types/service-worker.d.ts +6 -0
  62. package/style/base.css +5 -0
  63. package/lib/settings/settings-connector.d.ts +0 -31
  64. package/lib/settings/settings-connector.js +0 -61
  65. package/src/settings/settings-connector.ts +0 -88
@@ -0,0 +1,146 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "properties": {
5
+ "numa": {
6
+ "type": "boolean"
7
+ },
8
+ "numCtx": {
9
+ "type": "number"
10
+ },
11
+ "numBatch": {
12
+ "type": "number"
13
+ },
14
+ "numGpu": {
15
+ "type": "number"
16
+ },
17
+ "mainGpu": {
18
+ "type": "number"
19
+ },
20
+ "lowVram": {
21
+ "type": "boolean"
22
+ },
23
+ "f16Kv": {
24
+ "type": "boolean"
25
+ },
26
+ "logitsAll": {
27
+ "type": "boolean"
28
+ },
29
+ "vocabOnly": {
30
+ "type": "boolean"
31
+ },
32
+ "useMmap": {
33
+ "type": "boolean"
34
+ },
35
+ "useMlock": {
36
+ "type": "boolean"
37
+ },
38
+ "embeddingOnly": {
39
+ "type": "boolean"
40
+ },
41
+ "numThread": {
42
+ "type": "number"
43
+ },
44
+ "numKeep": {
45
+ "type": "number"
46
+ },
47
+ "seed": {
48
+ "type": "number"
49
+ },
50
+ "numPredict": {
51
+ "type": "number"
52
+ },
53
+ "topK": {
54
+ "type": "number"
55
+ },
56
+ "topP": {
57
+ "type": "number"
58
+ },
59
+ "tfsZ": {
60
+ "type": "number"
61
+ },
62
+ "typicalP": {
63
+ "type": "number"
64
+ },
65
+ "repeatLastN": {
66
+ "type": "number"
67
+ },
68
+ "temperature": {
69
+ "type": "number"
70
+ },
71
+ "repeatPenalty": {
72
+ "type": "number"
73
+ },
74
+ "presencePenalty": {
75
+ "type": "number"
76
+ },
77
+ "frequencyPenalty": {
78
+ "type": "number"
79
+ },
80
+ "mirostat": {
81
+ "type": "number"
82
+ },
83
+ "mirostatTau": {
84
+ "type": "number"
85
+ },
86
+ "mirostatEta": {
87
+ "type": "number"
88
+ },
89
+ "penalizeNewline": {
90
+ "type": "boolean"
91
+ },
92
+ "keepAlive": {
93
+ "type": [
94
+ "string",
95
+ "number"
96
+ ],
97
+ "default": "5m"
98
+ },
99
+ "stop": {
100
+ "type": "array",
101
+ "items": {
102
+ "type": "string"
103
+ }
104
+ },
105
+ "disableStreaming": {
106
+ "type": "boolean",
107
+ "description": "Whether to disable streaming.\n\nIf streaming is bypassed, then `stream()` will defer to `invoke()`.\n\n- If true, will always bypass streaming case.\n- If false (default), will always use streaming case if available."
108
+ },
109
+ "model": {
110
+ "type": "string",
111
+ "description": "The model to invoke. If the model does not exist, it will be pulled.",
112
+ "default": ""
113
+ },
114
+ "baseUrl": {
115
+ "type": "string",
116
+ "description": "The host URL of the Ollama server.",
117
+ "default": ""
118
+ },
119
+ "headers": {
120
+ "type": "object",
121
+ "additionalProperties": false,
122
+ "description": "Optional HTTP Headers to include in the request."
123
+ },
124
+ "checkOrPullModel": {
125
+ "type": "boolean",
126
+ "description": "Whether or not to check the model exists on the local machine before invoking it. If set to `true`, the model will be pulled if it does not exist.",
127
+ "default": false
128
+ },
129
+ "streaming": {
130
+ "type": "boolean"
131
+ },
132
+ "format": {
133
+ "anyOf": [
134
+ {
135
+ "type": "string"
136
+ },
137
+ {
138
+ "type": "object"
139
+ }
140
+ ]
141
+ }
142
+ },
143
+ "additionalProperties": false,
144
+ "description": "Input to chat model class.",
145
+ "definitions": {}
146
+ }
@@ -1,9 +1,7 @@
1
1
  import { CompletionHandler, IInlineCompletionContext } from '@jupyterlab/completer';
2
- import { BaseChatModel } from '@langchain/core/language_models/chat_models';
3
2
  import { BaseCompleter, IBaseCompleter } from '../../base-completer';
4
3
  export declare class OpenAICompleter implements IBaseCompleter {
5
4
  constructor(options: BaseCompleter.IOptions);
6
- get completer(): BaseChatModel;
7
5
  /**
8
6
  * Getter and setter for the initial prompt.
9
7
  */
@@ -3,12 +3,8 @@ import { ChatOpenAI } from '@langchain/openai';
3
3
  import { COMPLETION_SYSTEM_PROMPT } from '../../provider';
4
4
  export class OpenAICompleter {
5
5
  constructor(options) {
6
- this._prompt = COMPLETION_SYSTEM_PROMPT;
7
6
  this._completer = new ChatOpenAI({ ...options.settings });
8
7
  }
9
- get completer() {
10
- return this._completer;
11
- }
12
8
  /**
13
9
  * Getter and setter for the initial prompt.
14
10
  */
@@ -48,4 +44,6 @@ export class OpenAICompleter {
48
44
  return { items: [] };
49
45
  }
50
46
  }
47
+ _completer;
48
+ _prompt = COMPLETION_SYSTEM_PROMPT;
51
49
  }
@@ -0,0 +1,27 @@
1
+ import { CompletionHandler, IInlineCompletionContext } from '@jupyterlab/completer';
2
+ import { ChatWebLLM } from '@langchain/community/chat_models/webllm';
3
+ import { BaseCompleter, IBaseCompleter } from '../../base-completer';
4
+ export declare class WebLLMCompleter implements IBaseCompleter {
5
+ constructor(options: BaseCompleter.IOptions);
6
+ /**
7
+ * Initialize the WebLLM model
8
+ */
9
+ private _initializeModel;
10
+ /**
11
+ * Getter and setter for the initial prompt.
12
+ */
13
+ get prompt(): string;
14
+ set prompt(value: string);
15
+ get provider(): ChatWebLLM;
16
+ fetch(request: CompletionHandler.IRequest, context: IInlineCompletionContext): Promise<{
17
+ items: {
18
+ insertText: string;
19
+ }[];
20
+ }>;
21
+ private _completer;
22
+ private _prompt;
23
+ private _isInitialized;
24
+ private _isInitializing;
25
+ private _initError;
26
+ private _abortController;
27
+ }
@@ -0,0 +1,136 @@
1
+ import { HumanMessage, SystemMessage } from '@langchain/core/messages';
2
+ import { ChatWebLLM } from '@langchain/community/chat_models/webllm';
3
+ import { COMPLETION_SYSTEM_PROMPT } from '../../provider';
4
+ /**
5
+ * Regular expression to match the '```' string at the start of a string.
6
+ * So the completions returned by the LLM can still be kept after removing the code block formatting.
7
+ *
8
+ * For example, if the response contains the following content after typing `import pandas`:
9
+ *
10
+ * ```python
11
+ * as pd
12
+ * ```
13
+ *
14
+ * The formatting string after removing the code block delimiters will be:
15
+ *
16
+ * as pd
17
+ */
18
+ const CODE_BLOCK_START_REGEX = /^```(?:[a-zA-Z]+)?\n?/;
19
+ /**
20
+ * Regular expression to match the '```' string at the end of a string.
21
+ */
22
+ const CODE_BLOCK_END_REGEX = /```$/;
23
+ export class WebLLMCompleter {
24
+ constructor(options) {
25
+ const model = options.settings.model;
26
+ // provide model separately since ChatWebLLM expects it
27
+ this._completer = new ChatWebLLM({
28
+ ...options.settings,
29
+ model
30
+ });
31
+ // Initialize the model and track its status
32
+ this._isInitialized = false;
33
+ this._isInitializing = false;
34
+ this._initError = null;
35
+ void this._initializeModel();
36
+ }
37
+ /**
38
+ * Initialize the WebLLM model
39
+ */
40
+ async _initializeModel() {
41
+ if (this._isInitialized || this._isInitializing) {
42
+ return;
43
+ }
44
+ this._isInitializing = true;
45
+ try {
46
+ await this._completer.initialize((progress) => {
47
+ console.log('WebLLM initialization progress:', progress);
48
+ });
49
+ this._isInitialized = true;
50
+ this._isInitializing = false;
51
+ console.log('WebLLM model successfully initialized');
52
+ }
53
+ catch (error) {
54
+ this._initError =
55
+ error instanceof Error ? error : new Error(String(error));
56
+ this._isInitializing = false;
57
+ console.error('Failed to initialize WebLLM model:', error);
58
+ }
59
+ }
60
+ /**
61
+ * Getter and setter for the initial prompt.
62
+ */
63
+ get prompt() {
64
+ return this._prompt;
65
+ }
66
+ set prompt(value) {
67
+ this._prompt = value;
68
+ }
69
+ get provider() {
70
+ return this._completer;
71
+ }
72
+ async fetch(request, context) {
73
+ // Abort any pending request
74
+ if (this._abortController) {
75
+ this._abortController.abort();
76
+ }
77
+ // Create a new abort controller for this request
78
+ this._abortController = new AbortController();
79
+ const signal = this._abortController.signal;
80
+ if (!this._isInitialized) {
81
+ if (this._initError) {
82
+ console.error('WebLLM model failed to initialize:', this._initError);
83
+ return { items: [] };
84
+ }
85
+ if (!this._isInitializing) {
86
+ // Try to initialize again if it's not currently initializing
87
+ await this._initializeModel();
88
+ }
89
+ else {
90
+ console.log('WebLLM model is still initializing, please try again later');
91
+ return { items: [] };
92
+ }
93
+ // Return empty if still not initialized
94
+ if (!this._isInitialized) {
95
+ return { items: [] };
96
+ }
97
+ }
98
+ const { text, offset: cursorOffset } = request;
99
+ const prompt = text.slice(0, cursorOffset);
100
+ const trimmedPrompt = prompt.trim();
101
+ const messages = [
102
+ new SystemMessage(this._prompt),
103
+ new HumanMessage(trimmedPrompt)
104
+ ];
105
+ try {
106
+ console.log('Trigger invoke');
107
+ const response = await this._completer.invoke(messages, { signal });
108
+ let content = response.content;
109
+ console.log('Response content:', content);
110
+ if (CODE_BLOCK_START_REGEX.test(content)) {
111
+ content = content
112
+ .replace(CODE_BLOCK_START_REGEX, '')
113
+ .replace(CODE_BLOCK_END_REGEX, '');
114
+ }
115
+ const items = [{ insertText: content }];
116
+ return {
117
+ items
118
+ };
119
+ }
120
+ catch (error) {
121
+ if (error instanceof Error) {
122
+ console.error('Error fetching completion from WebLLM:', error.message);
123
+ }
124
+ else {
125
+ console.error('Unknown error fetching completion from WebLLM:', error);
126
+ }
127
+ return { items: [] };
128
+ }
129
+ }
130
+ _completer;
131
+ _prompt = COMPLETION_SYSTEM_PROMPT;
132
+ _isInitialized = false;
133
+ _isInitializing = false;
134
+ _initError = null;
135
+ _abortController = null;
136
+ }
@@ -0,0 +1,6 @@
1
+ declare const _default: "\nWebLLM enables running LLMs directly in your browser, making it possible to use AI features without sending data to external servers.\n\n<i class=\"fas fa-info-circle\"></i> WebLLM runs models entirely in your browser, so initial model download may be large (100MB-2GB depending on the model).\n\n<i class=\"fas fa-exclamation-triangle\"></i> <strong>Requirements:</strong> WebLLM requires a browser with WebGPU support (Chrome 113+, Edge 113+, or Safari 17+). It will not work on older browsers or browsers without WebGPU enabled.\n\n1. Enter a model in the JupyterLab settings under the **Ai providers** section. Select the `WebLLM` provider and type the model you want to use.\n2. When you first use WebLLM, your browser will download the model. A progress notification will appear:\n3. Once loaded, use the chat\n4. Example of available models:\n - Llama-3.2-1B-Instruct-q4f32_1-MLC\n - Mistral-7B-Instruct-v0.3-q4f32_1-MLC\n - Qwen3-0.6B-q4f32_1-MLC\n5. See the full list of models: https://github.com/mlc-ai/web-llm/blob/632d34725629b480b5b2772379ef5c150b1286f0/src/config.ts#L303-L309\n\n<i class=\"fas fa-exclamation-triangle\"></i> Model performance depends on your device's hardware capabilities. More powerful devices will run models faster. Some larger models may not work well on devices with limited GPU memory or may experience slow response times.\n";
2
+ export default _default;
3
+ /**
4
+ * Check if the browser supports WebLLM.
5
+ */
6
+ export declare function compatibilityCheck(): Promise<string | null>;
@@ -0,0 +1,32 @@
1
+ export default `
2
+ WebLLM enables running LLMs directly in your browser, making it possible to use AI features without sending data to external servers.
3
+
4
+ <i class="fas fa-info-circle"></i> WebLLM runs models entirely in your browser, so initial model download may be large (100MB-2GB depending on the model).
5
+
6
+ <i class="fas fa-exclamation-triangle"></i> <strong>Requirements:</strong> WebLLM requires a browser with WebGPU support (Chrome 113+, Edge 113+, or Safari 17+). It will not work on older browsers or browsers without WebGPU enabled.
7
+
8
+ 1. Enter a model in the JupyterLab settings under the **Ai providers** section. Select the \`WebLLM\` provider and type the model you want to use.
9
+ 2. When you first use WebLLM, your browser will download the model. A progress notification will appear:
10
+ 3. Once loaded, use the chat
11
+ 4. Example of available models:
12
+ - Llama-3.2-1B-Instruct-q4f32_1-MLC
13
+ - Mistral-7B-Instruct-v0.3-q4f32_1-MLC
14
+ - Qwen3-0.6B-q4f32_1-MLC
15
+ 5. See the full list of models: https://github.com/mlc-ai/web-llm/blob/632d34725629b480b5b2772379ef5c150b1286f0/src/config.ts#L303-L309
16
+
17
+ <i class="fas fa-exclamation-triangle"></i> Model performance depends on your device's hardware capabilities. More powerful devices will run models faster. Some larger models may not work well on devices with limited GPU memory or may experience slow response times.
18
+ `;
19
+ /**
20
+ * Check if the browser supports WebLLM.
21
+ */
22
+ export async function compatibilityCheck() {
23
+ // Check if the browser supports the ChromeAI model
24
+ if (typeof navigator === 'undefined' || !('gpu' in navigator)) {
25
+ return 'Your browser does not support WebLLM, it does not support required WebGPU.';
26
+ }
27
+ if ((await navigator.gpu.requestAdapter()) === null) {
28
+ return 'You may need to enable WebGPU, `await navigator.gpu.requestAdapter()` is null.';
29
+ }
30
+ // If the model is available, return null to indicate compatibility
31
+ return null;
32
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "properties": {
5
+ "disableStreaming": {
6
+ "type": "boolean",
7
+ "description": "Whether to disable streaming.\n\nIf streaming is bypassed, then `stream()` will defer to `invoke()`.\n\n- If true, will always bypass streaming case.\n- If false (default), will always use streaming case if available."
8
+ },
9
+ "temperature": {
10
+ "type": "number"
11
+ },
12
+ "model": {
13
+ "type": "string"
14
+ }
15
+ },
16
+ "required": [
17
+ "model"
18
+ ],
19
+ "additionalProperties": false,
20
+ "definitions": {}
21
+ }
@@ -1,21 +1,31 @@
1
+ import { Notification } from '@jupyterlab/apputils';
1
2
  import { ChatAnthropic } from '@langchain/anthropic';
3
+ import { ChatWebLLM } from '@langchain/community/chat_models/webllm';
2
4
  import { ChromeAI } from '@langchain/community/experimental/llms/chrome_ai';
3
5
  import { ChatMistralAI } from '@langchain/mistralai';
6
+ import { ChatOllama } from '@langchain/ollama';
4
7
  import { ChatOpenAI } from '@langchain/openai';
5
- import { IAIProviderRegistry } from '../tokens';
6
8
  // Import completers
7
9
  import { AnthropicCompleter } from './Anthropic/completer';
8
10
  import { ChromeCompleter } from './ChromeAI/completer';
9
11
  import { CodestralCompleter } from './MistralAI/completer';
12
+ import { OllamaCompleter } from './Ollama/completer';
10
13
  import { OpenAICompleter } from './OpenAI/completer';
14
+ import { WebLLMCompleter } from './WebLLM/completer';
11
15
  // Import Settings
12
16
  import AnthropicSettings from './Anthropic/settings-schema.json';
13
17
  import ChromeAISettings from './ChromeAI/settings-schema.json';
14
18
  import MistralAISettings from './MistralAI/settings-schema.json';
19
+ import OllamaAISettings from './Ollama/settings-schema.json';
15
20
  import OpenAISettings from './OpenAI/settings-schema.json';
21
+ import WebLLMSettings from './WebLLM/settings-schema.json';
16
22
  // Import instructions
17
- import ChromeAIInstructions from './ChromeAI/instructions';
23
+ import ChromeAIInstructions, { compatibilityCheck as chromeAICompatibilityCheck } from './ChromeAI/instructions';
18
24
  import MistralAIInstructions from './MistralAI/instructions';
25
+ import OllamaInstructions from './Ollama/instructions';
26
+ import WebLLMInstructions, { compatibilityCheck as webLLMCompatibilityCheck } from './WebLLM/instructions';
27
+ import { prebuiltAppConfig } from '@mlc-ai/web-llm';
28
+ import { IAIProviderRegistry } from '../tokens';
19
29
  // Build the AIProvider list
20
30
  const AIProviders = [
21
31
  {
@@ -32,7 +42,8 @@ const AIProviders = [
32
42
  chatModel: ChromeAI,
33
43
  completer: ChromeCompleter,
34
44
  instructions: ChromeAIInstructions,
35
- settingsSchema: ChromeAISettings
45
+ settingsSchema: ChromeAISettings,
46
+ compatibilityCheck: chromeAICompatibilityCheck
36
47
  },
37
48
  {
38
49
  name: 'MistralAI',
@@ -41,6 +52,13 @@ const AIProviders = [
41
52
  instructions: MistralAIInstructions,
42
53
  settingsSchema: MistralAISettings
43
54
  },
55
+ {
56
+ name: 'Ollama',
57
+ chatModel: ChatOllama,
58
+ completer: OllamaCompleter,
59
+ instructions: OllamaInstructions,
60
+ settingsSchema: OllamaAISettings
61
+ },
44
62
  {
45
63
  name: 'OpenAI',
46
64
  chatModel: ChatOpenAI,
@@ -48,7 +66,100 @@ const AIProviders = [
48
66
  settingsSchema: OpenAISettings
49
67
  }
50
68
  ];
51
- export const defaultProviderPlugins = AIProviders.map(provider => {
69
+ /**
70
+ * Register the WebLLM provider in a separate plugin since it creates notifications
71
+ * when the model is changed in the settings.
72
+ */
73
+ const webLLMProviderPlugin = {
74
+ id: '@jupyterlite/ai:webllm',
75
+ description: 'Register the WebLLM provider',
76
+ autoStart: true,
77
+ requires: [IAIProviderRegistry],
78
+ activate: (app, registry) => {
79
+ registry.add({
80
+ name: 'WebLLM',
81
+ chatModel: ChatWebLLM,
82
+ completer: WebLLMCompleter,
83
+ settingsSchema: WebLLMSettings,
84
+ instructions: WebLLMInstructions,
85
+ compatibilityCheck: webLLMCompatibilityCheck,
86
+ exposeChatModel: true
87
+ });
88
+ registry.providerChanged.connect(async (sender, args) => {
89
+ const { currentName, currentChatModel, chatError } = registry;
90
+ if (currentChatModel === null) {
91
+ Notification.emit(chatError, 'error', {
92
+ autoClose: 2000
93
+ });
94
+ return;
95
+ }
96
+ // TODO: implement a proper way to handle models that may need to be initialized before being used.
97
+ // Mostly applies to WebLLM and ChromeAI as they may need to download the model in the browser first.
98
+ if (currentName === 'WebLLM') {
99
+ const compatibilityError = await webLLMCompatibilityCheck();
100
+ if (compatibilityError) {
101
+ Notification.dismiss();
102
+ Notification.emit(compatibilityError, 'error', {
103
+ autoClose: 2000
104
+ });
105
+ return;
106
+ }
107
+ const model = currentChatModel;
108
+ if (model === null || !model.model) {
109
+ return;
110
+ }
111
+ // Find if the model is part of the prebuiltAppConfig
112
+ const modelRecord = prebuiltAppConfig.model_list.find(modelRecord => modelRecord.model_id === model.model);
113
+ if (!modelRecord) {
114
+ Notification.dismiss();
115
+ Notification.emit(`Model ${model.model} not found in the prebuiltAppConfig`, 'error', {
116
+ autoClose: 2000
117
+ });
118
+ return;
119
+ }
120
+ // create a notification
121
+ const notification = Notification.emit('Loading model...', 'in-progress', {
122
+ autoClose: false,
123
+ progress: 0
124
+ });
125
+ try {
126
+ void model.initialize(report => {
127
+ const { progress, text } = report;
128
+ if (progress === 1) {
129
+ Notification.update({
130
+ id: notification,
131
+ progress: 1,
132
+ message: `Model ${model.model} loaded successfully`,
133
+ type: 'success',
134
+ autoClose: 2000
135
+ });
136
+ return;
137
+ }
138
+ Notification.update({
139
+ id: notification,
140
+ progress: progress / 1,
141
+ message: text,
142
+ type: 'in-progress'
143
+ });
144
+ });
145
+ }
146
+ catch (err) {
147
+ Notification.update({
148
+ id: notification,
149
+ progress: 1,
150
+ message: `Error loading model ${model.model}`,
151
+ type: 'error',
152
+ autoClose: 2000
153
+ });
154
+ }
155
+ }
156
+ });
157
+ }
158
+ };
159
+ /**
160
+ * Register all default AI providers.
161
+ */
162
+ const aiProviderPlugins = AIProviders.map(provider => {
52
163
  return {
53
164
  id: `@jupyterlite/ai:${provider.name}`,
54
165
  autoStart: true,
@@ -58,3 +169,7 @@ export const defaultProviderPlugins = AIProviders.map(provider => {
58
169
  }
59
170
  };
60
171
  });
172
+ export const defaultProviderPlugins = [
173
+ webLLMProviderPlugin,
174
+ ...aiProviderPlugins
175
+ ];
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { IChatCommandRegistry } from '@jupyter/chat';
2
2
  import { JupyterFrontEndPlugin } from '@jupyterlab/application';
3
- import { ISettingConnector } from '@jupyterlab/settingregistry';
4
3
  import { IAIProviderRegistry } from './tokens';
5
- declare const _default: (JupyterFrontEndPlugin<void> | JupyterFrontEndPlugin<IChatCommandRegistry> | JupyterFrontEndPlugin<IAIProviderRegistry> | JupyterFrontEndPlugin<ISettingConnector>)[];
4
+ declare const _default: (JupyterFrontEndPlugin<void> | JupyterFrontEndPlugin<IChatCommandRegistry> | JupyterFrontEndPlugin<IAIProviderRegistry>)[];
6
5
  export default _default;
6
+ export { IAIProviderRegistry } from './tokens';