Skip to content

Commit e2b6477

Browse files
brichetjtpio
andauthored
Allow different providers for the chat and the completer (#105)
* The provider registry set the completer or chat provider separately, each having its settings * Make the settings panel allowing multiple providers * Fix default settings * Handle the settings storage/retrieval (settings registry and local storage) from the parent component * Apply suggestions from PR comments Co-authored-by: Jeremy Tuloup <591645+jtpio@users.noreply.github.com> * Rename type to 'ModelRole' --------- Co-authored-by: Jeremy Tuloup <591645+jtpio@users.noreply.github.com>
1 parent 747d068 commit e2b6477

File tree

7 files changed

+448
-135
lines changed

7 files changed

+448
-135
lines changed

schema/provider-registry.json

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"title": "AI provider",
2+
"title": "AI providers",
33
"description": "Provider registry settings",
44
"jupyter.lab.setting-icon": "@jupyterlite/ai:jupyternaut-lite",
55
"jupyter.lab.setting-icon-label": "JupyterLite AI provider",
@@ -11,10 +11,16 @@
1111
"description": "Whether to use or not the secrets manager. If not, secrets will be stored in the browser (local storage)",
1212
"default": true
1313
},
14-
"AIprovider": {
14+
"UniqueProvider": {
15+
"type": "boolean",
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+
"default": true
19+
},
20+
"AIproviders": {
1521
"type": "object",
16-
"title": "AI provider",
17-
"description": "The AI provider configuration",
22+
"title": "AI providers",
23+
"description": "The AI providers configuration",
1824
"default": {},
1925
"additionalProperties": true
2026
}

src/completion-provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export class CompletionProvider implements IInlineCompletionProvider {
2828
* Get the current completer name.
2929
*/
3030
get name(): string {
31-
return this._providerRegistry.currentName;
31+
return this._providerRegistry.currentName('completer');
3232
}
3333

3434
/**

src/default-providers/index.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import { IAIProvider, IAIProviderRegistry } from '../tokens';
4545
const AIProviders: IAIProvider[] = [
4646
{
4747
name: 'Anthropic',
48-
chatModel: ChatAnthropic,
48+
chat: ChatAnthropic,
4949
completer: AnthropicCompleter,
5050
settingsSchema: AnthropicSettings,
5151
errorMessage: (error: any) => error.error.error.message
@@ -54,29 +54,29 @@ const AIProviders: IAIProvider[] = [
5454
name: 'ChromeAI',
5555
// TODO: fix
5656
// @ts-expect-error: missing properties
57-
chatModel: ChromeAI,
57+
chat: ChromeAI,
5858
completer: ChromeCompleter,
5959
instructions: ChromeAIInstructions,
6060
settingsSchema: ChromeAISettings,
6161
compatibilityCheck: chromeAICompatibilityCheck
6262
},
6363
{
6464
name: 'MistralAI',
65-
chatModel: ChatMistralAI,
65+
chat: ChatMistralAI,
6666
completer: CodestralCompleter,
6767
instructions: MistralAIInstructions,
6868
settingsSchema: MistralAISettings
6969
},
7070
{
7171
name: 'Ollama',
72-
chatModel: ChatOllama,
72+
chat: ChatOllama,
7373
completer: OllamaCompleter,
7474
instructions: OllamaInstructions,
7575
settingsSchema: OllamaAISettings
7676
},
7777
{
7878
name: 'OpenAI',
79-
chatModel: ChatOpenAI,
79+
chat: ChatOpenAI,
8080
completer: OpenAICompleter,
8181
settingsSchema: OpenAISettings
8282
}
@@ -94,16 +94,16 @@ const webLLMProviderPlugin: JupyterFrontEndPlugin<void> = {
9494
activate: (app: JupyterFrontEnd, registry: IAIProviderRegistry) => {
9595
registry.add({
9696
name: 'WebLLM',
97-
chatModel: ChatWebLLM,
97+
chat: ChatWebLLM,
9898
completer: WebLLMCompleter,
9999
settingsSchema: WebLLMSettings,
100100
instructions: WebLLMInstructions,
101101
compatibilityCheck: webLLMCompatibilityCheck,
102102
exposeChatModel: true
103103
});
104104

105-
registry.providerChanged.connect(async (sender, args) => {
106-
const { currentName, currentChatModel, chatError } = registry;
105+
registry.providerChanged.connect(async (sender, role) => {
106+
const { currentChatModel, chatError } = registry;
107107
if (currentChatModel === null) {
108108
Notification.emit(chatError, 'error', {
109109
autoClose: 2000
@@ -113,7 +113,7 @@ const webLLMProviderPlugin: JupyterFrontEndPlugin<void> = {
113113

114114
// TODO: implement a proper way to handle models that may need to be initialized before being used.
115115
// Mostly applies to WebLLM and ChromeAI as they may need to download the model in the browser first.
116-
if (currentName === 'WebLLM') {
116+
if (registry.currentName(role) === 'WebLLM') {
117117
const compatibilityError = await webLLMCompatibilityCheck();
118118

119119
if (compatibilityError) {

src/index.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ const providerRegistryPlugin: JupyterFrontEndPlugin<IAIProviderRegistry> =
188188
});
189189

190190
editorRegistry.addRenderer(
191-
`${PLUGIN_IDS.providerRegistry}.AIprovider`,
191+
`${PLUGIN_IDS.providerRegistry}.AIproviders`,
192192
aiSettingsRenderer({
193193
providerRegistry,
194194
secretsToken: token,
@@ -204,14 +204,27 @@ const providerRegistryPlugin: JupyterFrontEndPlugin<IAIProviderRegistry> =
204204
delete settings.schema.properties?.['UseSecretsManager'];
205205
}
206206
const updateProvider = () => {
207-
// Update the settings to the AI providers.
208-
const providerSettings = (settings.get('AIprovider').composite ?? {
209-
provider: 'None'
210-
}) as ReadonlyPartialJSONObject;
211-
providerRegistry.setProvider({
212-
name: providerSettings.provider as string,
213-
settings: providerSettings
214-
});
207+
// Get the Ai provider settings.
208+
const providerSettings = settings.get('AIproviders')
209+
.composite as ReadonlyPartialJSONObject;
210+
211+
// Update completer provider.
212+
if (Object.keys(providerSettings).includes('completer')) {
213+
providerRegistry.setCompleterProvider(
214+
providerSettings['completer'] as ReadonlyPartialJSONObject
215+
);
216+
} else {
217+
providerRegistry.setCompleterProvider({});
218+
}
219+
220+
// Update chat provider.
221+
if (Object.keys(providerSettings).includes('chat')) {
222+
providerRegistry.setChatProvider(
223+
providerSettings['chat'] as ReadonlyPartialJSONObject
224+
);
225+
} else {
226+
providerRegistry.setChatProvider({});
227+
}
215228
};
216229

217230
settings.changed.connect(() => updateProvider());

0 commit comments

Comments
 (0)