@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.
Files changed (87) hide show
  1. package/README.md +1 -1
  2. package/lib/base-completer.d.ts +22 -5
  3. package/lib/base-completer.js +14 -1
  4. package/lib/chat-handler.d.ts +23 -11
  5. package/lib/chat-handler.js +66 -45
  6. package/lib/completion-provider.d.ts +2 -2
  7. package/lib/completion-provider.js +5 -4
  8. package/lib/components/stop-button.d.ts +0 -1
  9. package/lib/default-prompts.d.ts +2 -0
  10. package/lib/default-prompts.js +31 -0
  11. package/lib/default-providers/Anthropic/completer.d.ts +4 -11
  12. package/lib/default-providers/Anthropic/completer.js +5 -16
  13. package/lib/default-providers/ChromeAI/completer.d.ts +4 -11
  14. package/lib/default-providers/ChromeAI/completer.js +5 -16
  15. package/lib/default-providers/ChromeAI/instructions.d.ts +4 -0
  16. package/lib/default-providers/ChromeAI/instructions.js +18 -0
  17. package/lib/default-providers/ChromeAI/settings-schema.json +0 -3
  18. package/lib/default-providers/Gemini/completer.d.ts +12 -0
  19. package/lib/default-providers/Gemini/completer.js +48 -0
  20. package/lib/default-providers/Gemini/instructions.d.ts +2 -0
  21. package/lib/default-providers/Gemini/instructions.js +9 -0
  22. package/lib/default-providers/Gemini/settings-schema.json +64 -0
  23. package/lib/default-providers/MistralAI/completer.d.ts +10 -13
  24. package/lib/default-providers/MistralAI/completer.js +42 -52
  25. package/lib/default-providers/MistralAI/instructions.d.ts +1 -1
  26. package/lib/default-providers/MistralAI/instructions.js +2 -0
  27. package/lib/default-providers/Ollama/completer.d.ts +12 -0
  28. package/lib/default-providers/Ollama/completer.js +43 -0
  29. package/lib/default-providers/Ollama/instructions.d.ts +2 -0
  30. package/lib/default-providers/Ollama/instructions.js +70 -0
  31. package/lib/default-providers/Ollama/settings-schema.json +143 -0
  32. package/lib/default-providers/OpenAI/completer.d.ts +4 -11
  33. package/lib/default-providers/OpenAI/completer.js +8 -16
  34. package/lib/default-providers/OpenAI/settings-schema.json +88 -128
  35. package/lib/default-providers/WebLLM/completer.d.ts +21 -0
  36. package/lib/default-providers/WebLLM/completer.js +127 -0
  37. package/lib/default-providers/WebLLM/instructions.d.ts +6 -0
  38. package/lib/default-providers/WebLLM/instructions.js +32 -0
  39. package/lib/default-providers/WebLLM/settings-schema.json +19 -0
  40. package/lib/default-providers/index.js +127 -8
  41. package/lib/index.d.ts +3 -2
  42. package/lib/index.js +80 -36
  43. package/lib/provider.d.ts +48 -22
  44. package/lib/provider.js +254 -101
  45. package/lib/settings/index.d.ts +1 -1
  46. package/lib/settings/index.js +1 -1
  47. package/lib/settings/panel.d.ts +151 -14
  48. package/lib/settings/panel.js +334 -145
  49. package/lib/settings/textarea.d.ts +2 -0
  50. package/lib/settings/textarea.js +18 -0
  51. package/lib/tokens.d.ts +45 -22
  52. package/lib/tokens.js +2 -1
  53. package/lib/types/ai-model.d.ts +24 -0
  54. package/lib/types/ai-model.js +5 -0
  55. package/package.json +19 -15
  56. package/schema/chat.json +1 -1
  57. package/schema/provider-registry.json +8 -8
  58. package/schema/system-prompts.json +22 -0
  59. package/src/base-completer.ts +38 -6
  60. package/src/chat-handler.ts +62 -31
  61. package/src/completion-provider.ts +3 -3
  62. package/src/default-prompts.ts +33 -0
  63. package/src/default-providers/Anthropic/completer.ts +5 -21
  64. package/src/default-providers/ChromeAI/completer.ts +5 -21
  65. package/src/default-providers/ChromeAI/instructions.ts +21 -0
  66. package/src/default-providers/Gemini/completer.ts +61 -0
  67. package/src/default-providers/Gemini/instructions.ts +9 -0
  68. package/src/default-providers/MistralAI/completer.ts +47 -65
  69. package/src/default-providers/MistralAI/instructions.ts +2 -0
  70. package/src/default-providers/Ollama/completer.ts +54 -0
  71. package/src/default-providers/Ollama/instructions.ts +70 -0
  72. package/src/default-providers/OpenAI/completer.ts +8 -21
  73. package/src/default-providers/WebLLM/completer.ts +151 -0
  74. package/src/default-providers/WebLLM/instructions.ts +33 -0
  75. package/src/default-providers/index.ts +158 -18
  76. package/src/index.ts +108 -40
  77. package/src/provider.ts +300 -109
  78. package/src/settings/index.ts +1 -1
  79. package/src/settings/panel.tsx +463 -101
  80. package/src/settings/textarea.tsx +33 -0
  81. package/src/tokens.ts +49 -24
  82. package/src/types/ai-model.ts +37 -0
  83. package/src/types/service-worker.d.ts +6 -0
  84. package/style/base.css +34 -0
  85. package/lib/settings/settings-connector.d.ts +0 -31
  86. package/lib/settings/settings-connector.js +0 -61
  87. package/src/settings/settings-connector.ts +0 -88
@@ -0,0 +1,33 @@
1
+ import { ISettingRegistry } from '@jupyterlab/settingregistry';
2
+ import { IFormRenderer } from '@jupyterlab/ui-components';
3
+ import { FieldProps } from '@rjsf/utils';
4
+ import React, { useState } from 'react';
5
+
6
+ const TEXTAREA_CLASS = 'jp-AISettingsTextArea';
7
+
8
+ export const textArea: IFormRenderer = {
9
+ fieldRenderer: (props: FieldProps) => {
10
+ const settings: ISettingRegistry.ISettings = props.formContext.settings;
11
+ const schema = settings.schema.properties?.[props.name];
12
+ const [formData, setFormData] = useState<string>(props.formData);
13
+ settings.changed.connect(() => {
14
+ setFormData(settings.get(props.name).composite as string);
15
+ });
16
+ const onChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
17
+ settings.set(props.name, event.target.value);
18
+ };
19
+
20
+ return (
21
+ <>
22
+ {schema?.title && (
23
+ <h3 className="jp-FormGroup-fieldLabel jp-FormGroup-contentItem">
24
+ {schema.title}
25
+ </h3>
26
+ )}
27
+ <textarea className={TEXTAREA_CLASS} onChange={onChange}>
28
+ {formData}
29
+ </textarea>
30
+ </>
31
+ );
32
+ }
33
+ };
package/src/tokens.ts CHANGED
@@ -4,15 +4,19 @@ import { ISignal } from '@lumino/signaling';
4
4
  import { JSONSchema7 } from 'json-schema';
5
5
 
6
6
  import { IBaseCompleter } from './base-completer';
7
+ import { AIChatModel, AICompleter } from './types/ai-model';
7
8
 
8
9
  export const PLUGIN_IDS = {
9
10
  chat: '@jupyterlite/ai:chat',
10
11
  chatCommandRegistry: '@jupyterlite/ai:autocompletion-registry',
11
12
  completer: '@jupyterlite/ai:completer',
12
13
  providerRegistry: '@jupyterlite/ai:provider-registry',
13
- settingsConnector: '@jupyterlite/ai:settings-connector'
14
+ settingsConnector: '@jupyterlite/ai:settings-connector',
15
+ systemPrompts: '@jupyterlite/ai:system-prompts'
14
16
  };
15
17
 
18
+ export type ModelRole = 'chat' | 'completer';
19
+
16
20
  export interface IDict<T = any> {
17
21
  [key: string]: T;
18
22
  }
@@ -32,7 +36,7 @@ export interface IAIProvider {
32
36
  /**
33
37
  * The chat model class to use.
34
38
  */
35
- chatModel?: IType<BaseChatModel>;
39
+ chat?: IType<BaseChatModel>;
36
40
  /**
37
41
  * The completer class to use.
38
42
  */
@@ -51,6 +55,20 @@ export interface IAIProvider {
51
55
  * Default to `(error) => error.message`.
52
56
  */
53
57
  errorMessage?: (error: any) => string;
58
+ /**
59
+ * Compatibility check function, to determine if the provider is compatible with the
60
+ * current environment.
61
+ */
62
+ compatibilityCheck?: () => Promise<string | null>;
63
+ /**
64
+ * Whether to expose or not the chat model.
65
+ *
66
+ * ### CAUTION
67
+ * This flag will expose the whole chat model API, which may contain private keys.
68
+ * Be sure to use it with a model that does not expose sensitive information in the
69
+ * API.
70
+ */
71
+ exposeChatModel?: boolean;
54
72
  }
55
73
 
56
74
  /**
@@ -68,15 +86,23 @@ export interface IAIProviderRegistry {
68
86
  /**
69
87
  * Get the current provider name.
70
88
  */
71
- currentName: string;
89
+ currentName(role: ModelRole): string;
72
90
  /**
73
91
  * Get the current completer of the completion provider.
74
92
  */
75
- currentCompleter: IBaseCompleter | null;
93
+ currentCompleter: AICompleter | null;
94
+ /**
95
+ * Getter/setter for the completer system prompt.
96
+ */
97
+ completerSystemPrompt: string;
76
98
  /**
77
99
  * Get the current llm chat model.
78
100
  */
79
- currentChatModel: BaseChatModel | null;
101
+ currentChatModel: AIChatModel | null;
102
+ /**
103
+ * Getter/setter for the chat system prompt.
104
+ */
105
+ chatSystemPrompt: string;
80
106
  /**
81
107
  * Get the settings schema of a given provider.
82
108
  */
@@ -85,21 +111,34 @@ export interface IAIProviderRegistry {
85
111
  * Get the instructions of a given provider.
86
112
  */
87
113
  getInstructions(provider: string): string | undefined;
114
+ /**
115
+ * Get the compatibility check function of a given provider.
116
+ */
117
+ getCompatibilityCheck(
118
+ provider: string
119
+ ): (() => Promise<string | null>) | undefined;
88
120
  /**
89
121
  * Format an error message from the current provider.
90
122
  */
91
123
  formatErrorMessage(error: any): string;
92
124
  /**
93
- * Set the providers (chat model and completer).
94
- * Creates the providers if the name has changed, otherwise only updates their config.
125
+ * Set the completer provider.
126
+ * Creates the provider if the name has changed, otherwise only updates its config.
95
127
  *
96
- * @param options - an object with the name and the settings of the provider to use.
128
+ * @param options - An object with the name and the settings of the provider to use.
97
129
  */
98
- setProvider(options: ISetProviderOptions): void;
130
+ setCompleterProvider(settings: ReadonlyPartialJSONObject): void;
131
+ /**
132
+ * Set the chat provider.
133
+ * Creates the provider if the name has changed, otherwise only updates its config.
134
+ *
135
+ * @param options - An object with the name and the settings of the provider to use.
136
+ */
137
+ setChatProvider(settings: ReadonlyPartialJSONObject): void;
99
138
  /**
100
139
  * A signal emitting when the provider or its settings has changed.
101
140
  */
102
- readonly providerChanged: ISignal<IAIProviderRegistry, void>;
141
+ readonly providerChanged: ISignal<IAIProviderRegistry, ModelRole>;
103
142
  /**
104
143
  * Get the current chat error;
105
144
  */
@@ -110,20 +149,6 @@ export interface IAIProviderRegistry {
110
149
  readonly completerError: string;
111
150
  }
112
151
 
113
- /**
114
- * The set provider options.
115
- */
116
- export interface ISetProviderOptions {
117
- /**
118
- * The name of the provider.
119
- */
120
- name: string;
121
- /**
122
- * The settings of the provider.
123
- */
124
- settings: ReadonlyPartialJSONObject;
125
- }
126
-
127
152
  /**
128
153
  * The provider registry token.
129
154
  */
@@ -0,0 +1,37 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+
6
+ import {
7
+ CompletionHandler,
8
+ IInlineCompletionContext
9
+ } from '@jupyterlab/completer';
10
+ import { IterableReadableStream } from '@langchain/core/utils/stream';
11
+
12
+ /**
13
+ * The reduced AI chat model interface.
14
+ */
15
+ export type AIChatModel = {
16
+ /**
17
+ * The stream function of the chat model.
18
+ */
19
+ stream: (input: any, options?: any) => Promise<IterableReadableStream<any>>;
20
+ };
21
+
22
+ /**
23
+ * The reduced AI completer interface.
24
+ */
25
+ export type AICompleter = {
26
+ /**
27
+ * The fetch function of the completer.
28
+ */
29
+ fetch: (
30
+ request: CompletionHandler.IRequest,
31
+ context: IInlineCompletionContext
32
+ ) => Promise<any>;
33
+ /**
34
+ * The optional request completion function of the completer.
35
+ */
36
+ requestCompletion?: () => void;
37
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Type declarations for Service Worker APIs not included in standard TypeScript libs
3
+ */
4
+ interface ExtendableMessageEvent extends MessageEvent {
5
+ waitUntil(f: Promise<any>): void;
6
+ }
package/style/base.css CHANGED
@@ -9,3 +9,37 @@
9
9
  .jp-AISettingsInstructions {
10
10
  font-size: var(--jp-content-font-size1);
11
11
  }
12
+
13
+ .jp-AISettingsError {
14
+ color: var(--jp-error-color1);
15
+ font-size: var(--jp-content-font-size1);
16
+ }
17
+
18
+ .jp-AISettingsTextArea {
19
+ min-width: 400px;
20
+ min-height: 300px;
21
+ }
22
+
23
+ .jp-chat-welcome-message {
24
+ text-align: center;
25
+ max-width: 350px;
26
+ margin: 0 auto;
27
+ }
28
+
29
+ .jp-chat-welcome-message button[data-commandLinker-command] {
30
+ background: var(--jp-layout-color2);
31
+ border: 1px solid var(--jp-border-color1);
32
+ color: var(--jp-ui-font-color1);
33
+ border-radius: var(--jp-border-radius);
34
+ cursor: pointer;
35
+ font-size: inherit;
36
+ font-family: inherit;
37
+ padding: 2px 6px;
38
+ transition: all 0.2s ease;
39
+ }
40
+
41
+ .jp-chat-welcome-message button[data-commandLinker-command]:hover {
42
+ background: var(--jp-layout-color3);
43
+ border-color: var(--jp-brand-color1);
44
+ color: var(--jp-brand-color1);
45
+ }
@@ -1,31 +0,0 @@
1
- import { ISettingConnector, ISettingRegistry } from '@jupyterlab/settingregistry';
2
- import { DataConnector, IDataConnector } from '@jupyterlab/statedb';
3
- /**
4
- * A data connector for fetching settings.
5
- *
6
- * #### Notes
7
- * This connector adds a query parameter to the base services setting manager.
8
- */
9
- export declare class SettingConnector extends DataConnector<ISettingRegistry.IPlugin, string> implements ISettingConnector {
10
- constructor(connector: IDataConnector<ISettingRegistry.IPlugin, string>);
11
- set doNotSave(fields: string[]);
12
- /**
13
- * Fetch settings for a plugin.
14
- * @param id - The plugin ID
15
- *
16
- * #### Notes
17
- * The REST API requests are throttled at one request per plugin per 100ms.
18
- */
19
- fetch(id: string): Promise<ISettingRegistry.IPlugin | undefined>;
20
- list(query: 'ids'): Promise<{
21
- ids: string[];
22
- }>;
23
- list(query: 'active' | 'all'): Promise<{
24
- ids: string[];
25
- values: ISettingRegistry.IPlugin[];
26
- }>;
27
- save(id: string, raw: string): Promise<void>;
28
- private _connector;
29
- private _doNotSave;
30
- private _throttlers;
31
- }
@@ -1,61 +0,0 @@
1
- import { PageConfig } from '@jupyterlab/coreutils';
2
- import { DataConnector } from '@jupyterlab/statedb';
3
- import { Throttler } from '@lumino/polling';
4
- import * as json5 from 'json5';
5
- import { SECRETS_REPLACEMENT } from '.';
6
- /**
7
- * A data connector for fetching settings.
8
- *
9
- * #### Notes
10
- * This connector adds a query parameter to the base services setting manager.
11
- */
12
- export class SettingConnector extends DataConnector {
13
- constructor(connector) {
14
- super();
15
- this._doNotSave = [];
16
- this._throttlers = Object.create(null);
17
- this._connector = connector;
18
- }
19
- set doNotSave(fields) {
20
- this._doNotSave = [...fields];
21
- }
22
- /**
23
- * Fetch settings for a plugin.
24
- * @param id - The plugin ID
25
- *
26
- * #### Notes
27
- * The REST API requests are throttled at one request per plugin per 100ms.
28
- */
29
- fetch(id) {
30
- const throttlers = this._throttlers;
31
- if (!(id in throttlers)) {
32
- throttlers[id] = new Throttler(() => this._connector.fetch(id), 100);
33
- }
34
- return throttlers[id].invoke();
35
- }
36
- async list(query = 'all') {
37
- const { isDisabled } = PageConfig.Extension;
38
- const { ids, values } = await this._connector.list(query === 'ids' ? 'ids' : undefined);
39
- if (query === 'all') {
40
- return { ids, values };
41
- }
42
- if (query === 'ids') {
43
- return { ids };
44
- }
45
- return {
46
- ids: ids.filter(id => !isDisabled(id)),
47
- values: values.filter(({ id }) => !isDisabled(id))
48
- };
49
- }
50
- async save(id, raw) {
51
- const settings = json5.parse(raw);
52
- // Replace secrets fields with the replacement string.
53
- // Create the field if it does not exist in settings.
54
- this._doNotSave.forEach(field => {
55
- if (settings['AIprovider'] !== undefined) {
56
- settings['AIprovider'][field] = SECRETS_REPLACEMENT;
57
- }
58
- });
59
- await this._connector.save(id, json5.stringify(settings, null, 2));
60
- }
61
- }
@@ -1,88 +0,0 @@
1
- import { PageConfig } from '@jupyterlab/coreutils';
2
- import {
3
- ISettingConnector,
4
- ISettingRegistry
5
- } from '@jupyterlab/settingregistry';
6
- import { DataConnector, IDataConnector } from '@jupyterlab/statedb';
7
- import { Throttler } from '@lumino/polling';
8
- import * as json5 from 'json5';
9
-
10
- import { SECRETS_REPLACEMENT } from '.';
11
-
12
- /**
13
- * A data connector for fetching settings.
14
- *
15
- * #### Notes
16
- * This connector adds a query parameter to the base services setting manager.
17
- */
18
- export class SettingConnector
19
- extends DataConnector<ISettingRegistry.IPlugin, string>
20
- implements ISettingConnector
21
- {
22
- constructor(connector: IDataConnector<ISettingRegistry.IPlugin, string>) {
23
- super();
24
- this._connector = connector;
25
- }
26
-
27
- set doNotSave(fields: string[]) {
28
- this._doNotSave = [...fields];
29
- }
30
-
31
- /**
32
- * Fetch settings for a plugin.
33
- * @param id - The plugin ID
34
- *
35
- * #### Notes
36
- * The REST API requests are throttled at one request per plugin per 100ms.
37
- */
38
- fetch(id: string): Promise<ISettingRegistry.IPlugin | undefined> {
39
- const throttlers = this._throttlers;
40
- if (!(id in throttlers)) {
41
- throttlers[id] = new Throttler(() => this._connector.fetch(id), 100);
42
- }
43
- return throttlers[id].invoke();
44
- }
45
-
46
- async list(query: 'ids'): Promise<{ ids: string[] }>;
47
- async list(
48
- query: 'active' | 'all'
49
- ): Promise<{ ids: string[]; values: ISettingRegistry.IPlugin[] }>;
50
- async list(
51
- query: 'active' | 'all' | 'ids' = 'all'
52
- ): Promise<{ ids: string[]; values?: ISettingRegistry.IPlugin[] }> {
53
- const { isDisabled } = PageConfig.Extension;
54
- const { ids, values } = await this._connector.list(
55
- query === 'ids' ? 'ids' : undefined
56
- );
57
-
58
- if (query === 'all') {
59
- return { ids, values };
60
- }
61
-
62
- if (query === 'ids') {
63
- return { ids };
64
- }
65
-
66
- return {
67
- ids: ids.filter(id => !isDisabled(id)),
68
- values: values.filter(({ id }) => !isDisabled(id))
69
- };
70
- }
71
-
72
- async save(id: string, raw: string): Promise<void> {
73
- const settings = json5.parse(raw);
74
-
75
- // Replace secrets fields with the replacement string.
76
- // Create the field if it does not exist in settings.
77
- this._doNotSave.forEach(field => {
78
- if (settings['AIprovider'] !== undefined) {
79
- settings['AIprovider'][field] = SECRETS_REPLACEMENT;
80
- }
81
- });
82
- await this._connector.save(id, json5.stringify(settings, null, 2));
83
- }
84
-
85
- private _connector: IDataConnector<ISettingRegistry.IPlugin, string>;
86
- private _doNotSave: string[] = [];
87
- private _throttlers: { [key: string]: Throttler } = Object.create(null);
88
- }