@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
package/README.md CHANGED
@@ -14,7 +14,7 @@ AI code completions and chat for JupyterLab, Notebook 7 and JupyterLite ✨
14
14
  > To enable more AI providers in JupyterLab and Jupyter Notebook, we recommend using the [Jupyter AI](https://github.com/jupyterlab/jupyter-ai) extension directly.
15
15
  > At the moment Jupyter AI is not compatible with JupyterLite, but might be to some extent in the future.
16
16
 
17
- - JupyterLab >= 4.4.0a0 or Notebook >= 7.4.0a0
17
+ - JupyterLab >= 4.4.0 or Notebook >= 7.4.0
18
18
 
19
19
  ## ✨ Try it in your browser ✨
20
20
 
@@ -1,15 +1,12 @@
1
1
  import { CompletionHandler, IInlineCompletionContext } from '@jupyterlab/completer';
2
2
  import { BaseLanguageModel } from '@langchain/core/language_models/base';
3
3
  import { ReadonlyPartialJSONObject } from '@lumino/coreutils';
4
+ import { IAIProviderRegistry } from './tokens';
4
5
  export interface IBaseCompleter {
5
- /**
6
- * The LLM completer.
7
- */
8
- completer: BaseLanguageModel;
9
6
  /**
10
7
  * The completion prompt.
11
8
  */
12
- prompt: string;
9
+ readonly systemPrompt: string;
13
10
  /**
14
11
  * The function to fetch a new completion.
15
12
  */
@@ -19,6 +16,19 @@ export interface IBaseCompleter {
19
16
  */
20
17
  fetch(request: CompletionHandler.IRequest, context: IInlineCompletionContext): Promise<any>;
21
18
  }
19
+ export declare abstract class BaseCompleter implements IBaseCompleter {
20
+ constructor(options: BaseCompleter.IOptions);
21
+ /**
22
+ * Get the system prompt for the completion.
23
+ */
24
+ get systemPrompt(): string;
25
+ /**
26
+ * The fetch request for the LLM completer.
27
+ */
28
+ abstract fetch(request: CompletionHandler.IRequest, context: IInlineCompletionContext): Promise<any>;
29
+ protected _providerRegistry: IAIProviderRegistry;
30
+ protected abstract _completer: BaseLanguageModel<any, any>;
31
+ }
22
32
  /**
23
33
  * The namespace for the base completer.
24
34
  */
@@ -27,6 +37,13 @@ export declare namespace BaseCompleter {
27
37
  * The options for the constructor of a completer.
28
38
  */
29
39
  interface IOptions {
40
+ /**
41
+ * The provider registry.
42
+ */
43
+ providerRegistry: IAIProviderRegistry;
44
+ /**
45
+ * The settings of the provider.
46
+ */
30
47
  settings: ReadonlyPartialJSONObject;
31
48
  }
32
49
  }
@@ -1 +1,14 @@
1
- export {};
1
+ import { DEFAULT_COMPLETION_SYSTEM_PROMPT } from './default-prompts';
2
+ export class BaseCompleter {
3
+ constructor(options) {
4
+ this._providerRegistry = options.providerRegistry;
5
+ }
6
+ /**
7
+ * Get the system prompt for the completion.
8
+ */
9
+ get systemPrompt() {
10
+ return (this._providerRegistry.completerSystemPrompt ??
11
+ DEFAULT_COMPLETION_SYSTEM_PROMPT);
12
+ }
13
+ _providerRegistry;
14
+ }
@@ -1,44 +1,56 @@
1
- import { ChatCommand, ChatModel, IChatCommandProvider, IChatHistory, IChatMessage, IInputModel, INewMessage } from '@jupyter/chat';
2
- import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
1
+ import { ChatCommand, AbstractChatContext, AbstractChatModel, IChatCommandProvider, IChatContext, IChatHistory, IChatMessage, IChatModel, IInputModel, INewMessage } from '@jupyter/chat';
3
2
  import { IAIProviderRegistry } from './tokens';
3
+ import { AIChatModel } from './types/ai-model';
4
+ export declare const welcomeMessage: (providers: string[]) => string;
4
5
  export type ConnectionMessage = {
5
6
  type: 'connection';
6
7
  client_id: string;
7
8
  };
8
- export declare class ChatHandler extends ChatModel {
9
+ export declare class ChatHandler extends AbstractChatModel {
9
10
  constructor(options: ChatHandler.IOptions);
10
- get provider(): BaseChatModel | null;
11
+ get provider(): AIChatModel | null;
11
12
  /**
12
13
  * Getter and setter for the persona name.
13
14
  */
14
15
  get personaName(): string;
15
16
  set personaName(value: string);
16
17
  /**
17
- * Getter and setter for the initial prompt.
18
+ * Get/set the system prompt for the chat.
18
19
  */
19
- get prompt(): string;
20
- set prompt(value: string);
20
+ get systemPrompt(): string;
21
21
  sendMessage(message: INewMessage): Promise<boolean>;
22
22
  getHistory(): Promise<IChatHistory>;
23
23
  dispose(): void;
24
24
  messageAdded(message: IChatMessage): void;
25
25
  stopStreaming(): void;
26
+ createChatContext(): IChatContext;
26
27
  private _providerRegistry;
27
28
  private _personaName;
28
- private _prompt;
29
29
  private _errorMessage;
30
30
  private _history;
31
31
  private _defaultErrorMessage;
32
32
  private _controller;
33
33
  }
34
34
  export declare namespace ChatHandler {
35
- interface IOptions extends ChatModel.IOptions {
35
+ /**
36
+ * The options used to create a chat handler.
37
+ */
38
+ interface IOptions extends IChatModel.IOptions {
36
39
  providerRegistry: IAIProviderRegistry;
37
40
  }
41
+ /**
42
+ * The minimal chat context.
43
+ */
44
+ class ChatContext extends AbstractChatContext {
45
+ users: never[];
46
+ }
47
+ /**
48
+ * The chat command provider for the chat.
49
+ */
38
50
  class ClearCommandProvider implements IChatCommandProvider {
39
51
  id: string;
40
52
  private _slash_commands;
41
- getChatCommands(inputModel: IInputModel): Promise<ChatCommand[]>;
42
- handleChatCommand(command: ChatCommand, inputModel: IInputModel): Promise<void>;
53
+ listCommandCompletions(inputModel: IInputModel): Promise<ChatCommand[]>;
54
+ onSubmit(inputModel: IInputModel): Promise<void>;
43
55
  }
44
56
  }
@@ -2,10 +2,10 @@
2
2
  * Copyright (c) Jupyter Development Team.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
- import { ChatModel } from '@jupyter/chat';
5
+ import { AbstractChatContext, AbstractChatModel } from '@jupyter/chat';
6
6
  import { AIMessage, HumanMessage, mergeMessageRuns, SystemMessage } from '@langchain/core/messages';
7
7
  import { UUID } from '@lumino/coreutils';
8
- import { chatSystemPrompt } from './provider';
8
+ import { DEFAULT_CHAT_SYSTEM_PROMPT } from './default-prompts';
9
9
  import { jupyternautLiteIcon } from './icons';
10
10
  /**
11
11
  * The base64 encoded SVG string of the jupyternaut lite icon.
@@ -13,23 +13,23 @@ import { jupyternautLiteIcon } from './icons';
13
13
  */
14
14
  const AI_AVATAR_BASE64 = btoa(jupyternautLiteIcon.svgstr);
15
15
  const AI_AVATAR = `data:image/svg+xml;base64,${AI_AVATAR_BASE64}`;
16
- export class ChatHandler extends ChatModel {
16
+ export const welcomeMessage = (providers) => `
17
+ #### Ask JupyterLite AI
18
+
19
+
20
+ 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
21
+ the <img src="${AI_AVATAR}" width="16" height="16"> _AI provider_ settings.
22
+
23
+ The current providers that are available are _${providers.sort().join('_, _')}_.
24
+
25
+ To clear the chat, you can use the \`/clear\` command from the chat input.
26
+ `;
27
+ export class ChatHandler extends AbstractChatModel {
17
28
  constructor(options) {
18
29
  super(options);
19
- this._personaName = 'AI';
20
- this._errorMessage = '';
21
- this._history = { messages: [] };
22
- this._defaultErrorMessage = 'AI provider not configured';
23
- this._controller = null;
24
30
  this._providerRegistry = options.providerRegistry;
25
- this._prompt = chatSystemPrompt({
26
- provider_name: this._providerRegistry.currentName
27
- });
28
31
  this._providerRegistry.providerChanged.connect(() => {
29
32
  this._errorMessage = this._providerRegistry.chatError;
30
- this._prompt = chatSystemPrompt({
31
- provider_name: this._providerRegistry.currentName
32
- });
33
33
  });
34
34
  }
35
35
  get provider() {
@@ -52,16 +52,12 @@ export class ChatHandler extends ChatModel {
52
52
  this._personaName = value;
53
53
  }
54
54
  /**
55
- * Getter and setter for the initial prompt.
55
+ * Get/set the system prompt for the chat.
56
56
  */
57
- get prompt() {
58
- return this._prompt;
59
- }
60
- set prompt(value) {
61
- this._prompt = value;
57
+ get systemPrompt() {
58
+ return (this._providerRegistry.chatSystemPrompt ?? DEFAULT_CHAT_SYSTEM_PROMPT);
62
59
  }
63
60
  async sendMessage(message) {
64
- var _a;
65
61
  const body = message.body;
66
62
  if (body.startsWith('/clear')) {
67
63
  // TODO: do we need a clear method?
@@ -74,7 +70,7 @@ export class ChatHandler extends ChatModel {
74
70
  id: message.id,
75
71
  body,
76
72
  sender: { username: 'User' },
77
- time: Date.now(),
73
+ time: Private.getTimestampMs(),
78
74
  type: 'msg'
79
75
  };
80
76
  this.messageAdded(msg);
@@ -83,14 +79,14 @@ export class ChatHandler extends ChatModel {
83
79
  id: UUID.uuid4(),
84
80
  body: `**${this._errorMessage ? this._errorMessage : this._defaultErrorMessage}**`,
85
81
  sender: { username: 'ERROR' },
86
- time: Date.now(),
82
+ time: Private.getTimestampMs(),
87
83
  type: 'msg'
88
84
  };
89
85
  this.messageAdded(errorMsg);
90
86
  return false;
91
87
  }
92
88
  this._history.messages.push(msg);
93
- const messages = mergeMessageRuns([new SystemMessage(this._prompt)]);
89
+ const messages = mergeMessageRuns([new SystemMessage(this.systemPrompt)]);
94
90
  messages.push(...this._history.messages.map(msg => {
95
91
  if (msg.sender.username === 'User') {
96
92
  return new HumanMessage(msg.body);
@@ -98,20 +94,20 @@ export class ChatHandler extends ChatModel {
98
94
  return new AIMessage(msg.body);
99
95
  }));
100
96
  const sender = { username: this._personaName, avatar_url: AI_AVATAR };
101
- this.updateWriters([sender]);
97
+ this.updateWriters([{ user: sender }]);
102
98
  // create an empty message to be filled by the AI provider
103
99
  const botMsg = {
104
100
  id: UUID.uuid4(),
105
101
  body: '',
106
102
  sender,
107
- time: Date.now(),
103
+ time: Private.getTimestampMs(),
108
104
  type: 'msg'
109
105
  };
110
106
  let content = '';
111
107
  this._controller = new AbortController();
112
108
  try {
113
109
  for await (const chunk of await this._providerRegistry.currentChatModel.stream(messages, { signal: this._controller.signal })) {
114
- content += (_a = chunk.content) !== null && _a !== void 0 ? _a : chunk;
110
+ content += chunk.content ?? chunk;
115
111
  botMsg.body = content;
116
112
  this.messageAdded(botMsg);
117
113
  }
@@ -124,7 +120,7 @@ export class ChatHandler extends ChatModel {
124
120
  id: UUID.uuid4(),
125
121
  body: `**${error}**`,
126
122
  sender: { username: 'ERROR' },
127
- time: Date.now(),
123
+ time: Private.getTimestampMs(),
128
124
  type: 'msg'
129
125
  };
130
126
  this.messageAdded(errorMsg);
@@ -145,36 +141,61 @@ export class ChatHandler extends ChatModel {
145
141
  super.messageAdded(message);
146
142
  }
147
143
  stopStreaming() {
148
- var _a;
149
- (_a = this._controller) === null || _a === void 0 ? void 0 : _a.abort();
144
+ this._controller?.abort();
150
145
  }
146
+ createChatContext() {
147
+ return new ChatHandler.ChatContext({ model: this });
148
+ }
149
+ _providerRegistry;
150
+ _personaName = 'AI';
151
+ _errorMessage = '';
152
+ _history = { messages: [] };
153
+ _defaultErrorMessage = 'AI provider not configured';
154
+ _controller = null;
151
155
  }
152
156
  (function (ChatHandler) {
157
+ /**
158
+ * The minimal chat context.
159
+ */
160
+ class ChatContext extends AbstractChatContext {
161
+ users = [];
162
+ }
163
+ ChatHandler.ChatContext = ChatContext;
164
+ /**
165
+ * The chat command provider for the chat.
166
+ */
153
167
  class ClearCommandProvider {
154
- constructor() {
155
- this.id = '@jupyterlite/ai:clear-commands';
156
- this._slash_commands = [
157
- {
158
- name: '/clear',
159
- providerId: this.id,
160
- replaceWith: '/clear',
161
- description: 'Clear the chat'
162
- }
163
- ];
164
- }
165
- async getChatCommands(inputModel) {
166
- var _a, _b;
167
- const match = (_b = (_a = inputModel.currentWord) === null || _a === void 0 ? void 0 : _a.match(/^\/\w*/)) === null || _b === void 0 ? void 0 : _b[0];
168
+ id = '@jupyterlite/ai:clear-commands';
169
+ _slash_commands = [
170
+ {
171
+ name: '/clear',
172
+ providerId: this.id,
173
+ replaceWith: '/clear',
174
+ description: 'Clear the chat'
175
+ }
176
+ ];
177
+ async listCommandCompletions(inputModel) {
178
+ const match = inputModel.currentWord?.match(/^\/\w*/)?.[0];
168
179
  if (!match) {
169
180
  return [];
170
181
  }
171
182
  const commands = this._slash_commands.filter(cmd => cmd.name.startsWith(match));
172
183
  return commands;
173
184
  }
174
- async handleChatCommand(command, inputModel) {
185
+ async onSubmit(inputModel) {
175
186
  // no handling needed because `replaceWith` is set in each command.
176
187
  return;
177
188
  }
178
189
  }
179
190
  ChatHandler.ClearCommandProvider = ClearCommandProvider;
180
191
  })(ChatHandler || (ChatHandler = {}));
192
+ var Private;
193
+ (function (Private) {
194
+ /**
195
+ * Return the current timestamp in milliseconds.
196
+ */
197
+ function getTimestampMs() {
198
+ return Date.now() / 1000;
199
+ }
200
+ Private.getTimestampMs = getTimestampMs;
201
+ })(Private || (Private = {}));
@@ -1,6 +1,6 @@
1
1
  import { CompletionHandler, IInlineCompletionContext, IInlineCompletionProvider } from '@jupyterlab/completer';
2
- import { IBaseCompleter } from './base-completer';
3
2
  import { IAIProviderRegistry } from './tokens';
3
+ import { AICompleter } from './types/ai-model';
4
4
  /**
5
5
  * The generic completion provider to register to the completion provider manager.
6
6
  */
@@ -14,7 +14,7 @@ export declare class CompletionProvider implements IInlineCompletionProvider {
14
14
  /**
15
15
  * Get the current completer.
16
16
  */
17
- get completer(): IBaseCompleter | null;
17
+ get completer(): AICompleter | null;
18
18
  fetch(request: CompletionHandler.IRequest, context: IInlineCompletionContext): Promise<any>;
19
19
  private _providerRegistry;
20
20
  private _requestCompletion;
@@ -2,8 +2,8 @@
2
2
  * The generic completion provider to register to the completion provider manager.
3
3
  */
4
4
  export class CompletionProvider {
5
+ identifier = '@jupyterlite/ai';
5
6
  constructor(options) {
6
- this.identifier = '@jupyterlite/ai';
7
7
  this._providerRegistry = options.providerRegistry;
8
8
  this._requestCompletion = options.requestCompletion;
9
9
  this._providerRegistry.providerChanged.connect(() => {
@@ -16,7 +16,7 @@ export class CompletionProvider {
16
16
  * Get the current completer name.
17
17
  */
18
18
  get name() {
19
- return this._providerRegistry.currentName;
19
+ return this._providerRegistry.currentName('completer');
20
20
  }
21
21
  /**
22
22
  * Get the current completer.
@@ -25,7 +25,8 @@ export class CompletionProvider {
25
25
  return this._providerRegistry.currentCompleter;
26
26
  }
27
27
  async fetch(request, context) {
28
- var _a;
29
- return (_a = this.completer) === null || _a === void 0 ? void 0 : _a.fetch(request, context);
28
+ return this.completer?.fetch(request, context);
30
29
  }
30
+ _providerRegistry;
31
+ _requestCompletion;
31
32
  }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { InputToolbarRegistry } from '@jupyter/chat';
3
2
  /**
4
3
  * Properties of the stop button.
@@ -0,0 +1,2 @@
1
+ export declare const DEFAULT_CHAT_SYSTEM_PROMPT = "\nYou 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.\n";
2
+ export declare const DEFAULT_COMPLETION_SYSTEM_PROMPT = "\nYou are an application built to provide helpful code completion suggestions.\nYou should only produce code. Keep comments to minimum, use the\nprogramming language comment syntax. Produce clean code.\nThe code is written in JupyterLab, a data analysis and code development\nenvironment which can execute code extended with additional syntax for\ninteractive 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\ngive code passed as input, no explanation whatsoever.\nDo not include the prompt in the output, only the string that should be appended to the current input.\nHere is the code to complete:\n";
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ export const DEFAULT_CHAT_SYSTEM_PROMPT = `
6
+ You are Jupyternaut, a conversational assistant living in JupyterLab to help users.
7
+ You are not a language model, but rather an application built on a foundation model from $provider_name$.
8
+ You are talkative and you provide lots of specific details from the foundation model's context.
9
+ You may use Markdown to format your response.
10
+ If your response includes code, they must be enclosed in Markdown fenced code blocks (with triple backticks before and after).
11
+ If your response includes mathematical notation, they must be expressed in LaTeX markup and enclosed in LaTeX delimiters.
12
+ All dollar quantities (of USD) must be formatted in LaTeX, with the \`$\` symbol escaped by a single backslash \`\\\`.
13
+ - Example prompt: \`If I have \\\\$100 and spend \\\\$20, how much money do I have left?\`
14
+ - **Correct** response: \`You have \\(\\$80\\) remaining.\`
15
+ - **Incorrect** response: \`You have $80 remaining.\`
16
+ If you do not know the answer to a question, answer truthfully by responding that you do not know.
17
+ The following is a friendly conversation between you and a human.
18
+ `;
19
+ export const DEFAULT_COMPLETION_SYSTEM_PROMPT = `
20
+ You are an application built to provide helpful code completion suggestions.
21
+ You should only produce code. Keep comments to minimum, use the
22
+ programming language comment syntax. Produce clean code.
23
+ The code is written in JupyterLab, a data analysis and code development
24
+ environment which can execute code extended with additional syntax for
25
+ interactive features, such as magics.
26
+ Only give raw strings back, do not format the response using backticks.
27
+ The output should be a single string, and should only contain the code that will complete the
28
+ give code passed as input, no explanation whatsoever.
29
+ Do not include the prompt in the output, only the string that should be appended to the current input.
30
+ Here is the code to complete:
31
+ `;
@@ -1,19 +1,12 @@
1
1
  import { CompletionHandler, IInlineCompletionContext } from '@jupyterlab/completer';
2
- import { BaseChatModel } from '@langchain/core/language_models/chat_models';
3
- import { BaseCompleter, IBaseCompleter } from '../../base-completer';
4
- export declare class AnthropicCompleter implements IBaseCompleter {
2
+ import { ChatAnthropic } from '@langchain/anthropic';
3
+ import { BaseCompleter } from '../../base-completer';
4
+ export declare class AnthropicCompleter extends BaseCompleter {
5
5
  constructor(options: BaseCompleter.IOptions);
6
- get completer(): BaseChatModel;
7
- /**
8
- * Getter and setter for the initial prompt.
9
- */
10
- get prompt(): string;
11
- set prompt(value: string);
12
6
  fetch(request: CompletionHandler.IRequest, context: IInlineCompletionContext): Promise<{
13
7
  items: {
14
8
  insertText: string;
15
9
  }[];
16
10
  }>;
17
- private _completer;
18
- private _prompt;
11
+ protected _completer: ChatAnthropic;
19
12
  }
@@ -1,30 +1,18 @@
1
1
  import { ChatAnthropic } from '@langchain/anthropic';
2
2
  import { AIMessage, SystemMessage } from '@langchain/core/messages';
3
- import { COMPLETION_SYSTEM_PROMPT } from '../../provider';
4
- export class AnthropicCompleter {
3
+ import { BaseCompleter } from '../../base-completer';
4
+ export class AnthropicCompleter extends BaseCompleter {
5
5
  constructor(options) {
6
- this._prompt = COMPLETION_SYSTEM_PROMPT;
6
+ super(options);
7
7
  this._completer = new ChatAnthropic({ ...options.settings });
8
8
  }
9
- get completer() {
10
- return this._completer;
11
- }
12
- /**
13
- * Getter and setter for the initial prompt.
14
- */
15
- get prompt() {
16
- return this._prompt;
17
- }
18
- set prompt(value) {
19
- this._prompt = value;
20
- }
21
9
  async fetch(request, context) {
22
10
  const { text, offset: cursorOffset } = request;
23
11
  const prompt = text.slice(0, cursorOffset);
24
12
  // Anthropic does not allow whitespace at the end of the AIMessage
25
13
  const trimmedPrompt = prompt.trim();
26
14
  const messages = [
27
- new SystemMessage(this._prompt),
15
+ new SystemMessage(this.systemPrompt),
28
16
  new AIMessage(trimmedPrompt)
29
17
  ];
30
18
  try {
@@ -54,4 +42,5 @@ export class AnthropicCompleter {
54
42
  return { items: [] };
55
43
  }
56
44
  }
45
+ _completer;
57
46
  }
@@ -1,19 +1,12 @@
1
1
  import { CompletionHandler, IInlineCompletionContext } from '@jupyterlab/completer';
2
- import { LLM } from '@langchain/core/language_models/llms';
3
- import { BaseCompleter, IBaseCompleter } from '../../base-completer';
4
- export declare class ChromeCompleter implements IBaseCompleter {
2
+ import { ChromeAI } from '@langchain/community/experimental/llms/chrome_ai';
3
+ import { BaseCompleter } from '../../base-completer';
4
+ export declare class ChromeCompleter extends BaseCompleter {
5
5
  constructor(options: BaseCompleter.IOptions);
6
- /**
7
- * Getter and setter for the initial prompt.
8
- */
9
- get prompt(): string;
10
- set prompt(value: string);
11
- get completer(): LLM;
12
6
  fetch(request: CompletionHandler.IRequest, context: IInlineCompletionContext): Promise<{
13
7
  items: {
14
8
  insertText: string;
15
9
  }[];
16
10
  }>;
17
- private _completer;
18
- private _prompt;
11
+ protected _completer: ChromeAI;
19
12
  }
@@ -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 '../../provider';
3
+ import { BaseCompleter } from '../../base-completer';
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.
@@ -20,29 +20,17 @@ const CODE_BLOCK_START_REGEX = /^```(?:[a-zA-Z]+)?\n?/;
20
20
  * Regular expression to match the '```' string at the end of a string.
21
21
  */
22
22
  const CODE_BLOCK_END_REGEX = /```$/;
23
- export class ChromeCompleter {
23
+ export class ChromeCompleter extends BaseCompleter {
24
24
  constructor(options) {
25
- this._prompt = COMPLETION_SYSTEM_PROMPT;
25
+ super(options);
26
26
  this._completer = new ChromeAI({ ...options.settings });
27
27
  }
28
- /**
29
- * Getter and setter for the initial prompt.
30
- */
31
- get prompt() {
32
- return this._prompt;
33
- }
34
- set prompt(value) {
35
- this._prompt = value;
36
- }
37
- get completer() {
38
- return this._completer;
39
- }
40
28
  async fetch(request, context) {
41
29
  const { text, offset: cursorOffset } = request;
42
30
  const prompt = text.slice(0, cursorOffset);
43
31
  const trimmedPrompt = prompt.trim();
44
32
  const messages = [
45
- new SystemMessage(this._prompt),
33
+ new SystemMessage(this.systemPrompt),
46
34
  new HumanMessage(trimmedPrompt)
47
35
  ];
48
36
  try {
@@ -64,4 +52,5 @@ export class ChromeCompleter {
64
52
  return { items: [] };
65
53
  }
66
54
  }
55
+ _completer;
67
56
  }
@@ -1,2 +1,6 @@
1
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
2
  export default _default;
3
+ /**
4
+ * Check if the browser supports ChromeAI and the model is available.
5
+ */
6
+ export declare function compatibilityCheck(): Promise<string | null>;
@@ -22,3 +22,21 @@ During the download, ChromeAI may not be available via the extension.
22
22
 
23
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
24
  `;
25
+ /**
26
+ * Check if the browser supports ChromeAI and the model is available.
27
+ */
28
+ export async function compatibilityCheck() {
29
+ // Check if the browser supports the ChromeAI model
30
+ if (typeof window === 'undefined' ||
31
+ !('LanguageModel' in window) ||
32
+ window.LanguageModel === undefined ||
33
+ window.LanguageModel.availability === undefined) {
34
+ return 'Your browser does not support ChromeAI. Please use an updated chrome based browser like Google Chrome, and follow the instructions in settings to enable it.';
35
+ }
36
+ const languageModel = window.LanguageModel;
37
+ if (!(await languageModel.availability())) {
38
+ return 'The ChromeAI model is not available in your browser. Please ensure you have enabled the necessary flags in Google Chrome as described in the instructions in settings.';
39
+ }
40
+ // If the model is available, return null to indicate compatibility
41
+ return null;
42
+ }
@@ -11,9 +11,6 @@
11
11
  },
12
12
  "temperature": {
13
13
  "type": "number"
14
- },
15
- "systemPrompt": {
16
- "type": "string"
17
14
  }
18
15
  },
19
16
  "additionalProperties": false,
@@ -0,0 +1,12 @@
1
+ import { CompletionHandler, IInlineCompletionContext } from '@jupyterlab/completer';
2
+ import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
3
+ import { BaseCompleter } from '../../base-completer';
4
+ export declare class GeminiCompleter extends BaseCompleter {
5
+ constructor(options: BaseCompleter.IOptions);
6
+ fetch(request: CompletionHandler.IRequest, context: IInlineCompletionContext): Promise<{
7
+ items: {
8
+ insertText: string;
9
+ }[];
10
+ }>;
11
+ protected _completer: ChatGoogleGenerativeAI;
12
+ }