Skip to content

Commit 2db4816

Browse files
committed
Disable the tools button if the provider cannot handle it
1 parent ce2703b commit 2db4816

File tree

7 files changed

+138
-93
lines changed

7 files changed

+138
-93
lines changed

schema/chat.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@
2222
"title": "AI persona name",
2323
"description": "The name of the AI persona",
2424
"default": "Jupyternaut"
25-
},
26-
"UseTool": {
27-
"type": "boolean",
28-
"title": "Use tool",
29-
"description": "Whether tools are available in chat or not",
30-
"default": false
3125
}
3226
},
3327
"additionalProperties": false

schema/provider-registry.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
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+
"AllowToolsUsage": {
15+
"type": "boolean",
16+
"title": "Allow tools usage",
17+
"description": "Whether tools are available in chat or not",
18+
"default": true
19+
},
1420
"UniqueProvider": {
1521
"type": "boolean",
1622
"title": "Use the same provider for chat and completer",

src/chat-handler.ts

Lines changed: 16 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,10 @@ import {
2424
SystemMessage
2525
} from '@langchain/core/messages';
2626
import { UUID } from '@lumino/coreutils';
27-
import { ISignal, Signal } from '@lumino/signaling';
2827

2928
import { DEFAULT_CHAT_SYSTEM_PROMPT } from './default-prompts';
3029
import { jupyternautLiteIcon } from './icons';
31-
import { IAIProviderRegistry, IToolRegistry, Tool } from './tokens';
30+
import { IAIProviderRegistry, IToolRegistry } from './tokens';
3231
import { AIChatModel } from './types/ai-model';
3332

3433
/**
@@ -66,6 +65,13 @@ export class ChatHandler extends AbstractChatModel {
6665
});
6766
}
6867

68+
/**
69+
* The provider registry.
70+
*/
71+
get providerRegistry(): IAIProviderRegistry {
72+
return this._providerRegistry;
73+
}
74+
6975
/**
7076
* Get the tool registry.
7177
*/
@@ -104,44 +110,13 @@ export class ChatHandler extends AbstractChatModel {
104110
this._personaName = value;
105111
}
106112

107-
/**
108-
* Getter/setter for the use of tools.
109-
*/
110-
get useTool(): boolean {
111-
return this._useTool;
112-
}
113-
set useTool(value: boolean) {
114-
if (this._useTool !== value) {
115-
this._useTool = value;
116-
this._useToolChanged.emit(this._useTool);
117-
}
118-
}
119-
120-
/**
121-
* Get/set a tool, which will build an agent.
122-
*/
123-
get tools(): Tool[] {
124-
return this._tools;
125-
}
126-
set tools(value: Tool[]) {
127-
this._tools = value;
128-
this._providerRegistry.buildAgent(this._tools);
129-
}
130-
131-
/**
132-
* A signal triggered when the setting on tool usage has changed.
133-
*/
134-
get useToolChanged(): ISignal<ChatHandler, boolean> {
135-
return this._useToolChanged;
136-
}
137-
138113
/**
139114
* Get the system prompt for the chat.
140115
*/
141116
get systemPrompt(): string {
142117
let prompt =
143118
this._providerRegistry.chatSystemPrompt ?? DEFAULT_CHAT_SYSTEM_PROMPT;
144-
if (this.useTool && this.agent !== null) {
119+
if (this.agent !== null) {
145120
prompt = prompt.concat('\nPlease use the tool that is provided');
146121
}
147122
return prompt;
@@ -194,7 +169,7 @@ export class ChatHandler extends AbstractChatModel {
194169
const sender = { username: this._personaName, avatar_url: AI_AVATAR };
195170
this.updateWriters([{ user: sender }]);
196171

197-
if (this._useTool && this.agent !== null) {
172+
if (this.agent !== null) {
198173
return this._sendAgentMessage(this.agent, messages, sender);
199174
}
200175

@@ -337,10 +312,7 @@ export class ChatHandler extends AbstractChatModel {
337312
private _history: IChatHistory = { messages: [] };
338313
private _defaultErrorMessage = 'AI provider not configured';
339314
private _controller: AbortController | null = null;
340-
private _useTool: boolean = false;
341-
private _tools: Tool[] = [];
342315
private _toolRegistry?: IToolRegistry;
343-
private _useToolChanged = new Signal<ChatHandler, boolean>(this);
344316
}
345317

346318
export namespace ChatHandler {
@@ -359,34 +331,17 @@ export namespace ChatHandler {
359331
users = [];
360332

361333
/**
362-
* The tool registry.
363-
*/
364-
get toolsRegistry(): IToolRegistry | undefined {
365-
return (this._model as ChatHandler).toolRegistry;
366-
}
367-
368-
/**
369-
* Whether to use or not the tool.
334+
* The provider registry.
370335
*/
371-
get useTool(): boolean {
372-
return (this._model as ChatHandler).useTool;
336+
get providerRegistry(): IAIProviderRegistry {
337+
return (this._model as ChatHandler).providerRegistry;
373338
}
374339

375340
/**
376-
* A signal triggered when the setting on tool usage has changed.
377-
*/
378-
get useToolChanged(): ISignal<ChatHandler, boolean> {
379-
return (this._model as ChatHandler).useToolChanged;
380-
}
381-
382-
/**
383-
* Getter/setter of the tool to use.
341+
* The tool registry.
384342
*/
385-
get tools(): Tool[] {
386-
return (this._model as ChatHandler).tools;
387-
}
388-
set tools(value: Tool[]) {
389-
(this._model as ChatHandler).tools = value;
343+
get toolsRegistry(): IToolRegistry | undefined {
344+
return (this._model as ChatHandler).toolRegistry;
390345
}
391346
}
392347

src/components/tool-select.tsx

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { Menu, MenuItem, Tooltip, Typography } from '@mui/material';
1010
import React, { useCallback, useEffect, useState } from 'react';
1111

1212
import { ChatHandler } from '../chat-handler';
13-
import { Tool } from '../tokens';
13+
import { IAIProviderRegistry, Tool } from '../tokens';
1414

1515
const SELECT_ITEM_CLASS = 'jp-AIToolSelect-item';
1616

@@ -22,8 +22,10 @@ export function toolSelect(
2222
): JSX.Element {
2323
const chatContext = props.model.chatContext as ChatHandler.ChatContext;
2424
const toolRegistry = chatContext.toolsRegistry;
25+
const providerRegistry = chatContext.providerRegistry;
2526

26-
const [useTool, setUseTool] = useState<boolean>(chatContext.useTool);
27+
const [allowTools, setAllowTools] = useState<boolean>(true);
28+
const [agentAvailable, setAgentAvailable] = useState<boolean | undefined>();
2729
const [selectedTools, setSelectedTools] = useState<Tool[]>([]);
2830
const [tools, setTools] = useState<Tool[]>(toolRegistry?.tools || []);
2931
const [menuAnchorEl, setMenuAnchorEl] = useState<HTMLElement | null>(null);
@@ -47,7 +49,9 @@ export function toolSelect(
4749
currentTools.push(tool);
4850
}
4951
setSelectedTools(currentTools);
50-
chatContext.tools = currentTools;
52+
if (!providerRegistry.setTools(currentTools)) {
53+
setSelectedTools([]);
54+
}
5155
};
5256

5357
useEffect(() => {
@@ -59,21 +63,37 @@ export function toolSelect(
5963
}, [toolRegistry]);
6064

6165
useEffect(() => {
62-
const updateUseTool = (_: ChatHandler, value: boolean) => setUseTool(value);
63-
chatContext.useToolChanged.connect(updateUseTool);
66+
const updateAllowTools = (_: IAIProviderRegistry, value: boolean) =>
67+
setAllowTools(value);
68+
69+
const updateAgentAvailable = () =>
70+
setAgentAvailable(providerRegistry.isAgentAvailable());
71+
72+
providerRegistry.allowToolsChanged.connect(updateAllowTools);
73+
providerRegistry.providerChanged.connect(updateAgentAvailable);
74+
75+
setAllowTools(providerRegistry.allowTools);
76+
setAgentAvailable(providerRegistry.isAgentAvailable());
6477
return () => {
65-
chatContext.useToolChanged.disconnect(updateUseTool);
78+
providerRegistry.allowToolsChanged.disconnect(updateAllowTools);
79+
providerRegistry.providerChanged.disconnect(updateAgentAvailable);
6680
};
67-
}, [chatContext]);
81+
}, [providerRegistry]);
6882

69-
return useTool && tools.length ? (
83+
return allowTools && tools.length ? (
7084
<>
7185
<TooltippedButton
7286
onClick={e => {
7387
openMenu(e.currentTarget);
7488
}}
75-
disabled={!tools.length}
76-
tooltip="Tool"
89+
disabled={!agentAvailable}
90+
tooltip={
91+
agentAvailable === undefined
92+
? 'The provider is not set'
93+
: agentAvailable
94+
? 'Tools'
95+
: 'The provider or model cannot use tools'
96+
}
7797
buttonProps={{
7898
variant: 'contained',
7999
onKeyDown: e => {

src/index.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,19 +83,16 @@ const chatPlugin: JupyterFrontEndPlugin<void> = {
8383
let sendWithShiftEnter = false;
8484
let enableCodeToolbar = true;
8585
let personaName = 'AI';
86-
let useTool = false;
8786

8887
function loadSetting(setting: ISettingRegistry.ISettings): void {
8988
sendWithShiftEnter = setting.get('sendWithShiftEnter')
9089
.composite as boolean;
9190
enableCodeToolbar = setting.get('enableCodeToolbar').composite as boolean;
9291
personaName = setting.get('personaName').composite as string;
93-
useTool = (setting.get('UseTool').composite as boolean) ?? false;
9492

9593
// set the properties
9694
chatHandler.config = { sendWithShiftEnter, enableCodeToolbar };
9795
chatHandler.personaName = personaName;
98-
chatHandler.useTool = useTool;
9996
}
10097

10198
Promise.all([app.restored, settingsRegistry?.load(chatPlugin.id)])
@@ -208,16 +205,23 @@ const providerRegistryPlugin: JupyterFrontEndPlugin<IAIProviderRegistry> =
208205
})
209206
);
210207

208+
let allowToolsUsage = true;
209+
211210
settingRegistry
212211
.load(providerRegistryPlugin.id)
213212
.then(settings => {
214213
if (!secretsManager) {
215214
delete settings.schema.properties?.['UseSecretsManager'];
216215
}
217216

218-
const updateProvider = () => {
217+
const loadSetting = (setting: ISettingRegistry.ISettings) => {
218+
// Allowing usage of tools in the chat.
219+
allowToolsUsage =
220+
(setting.get('AllowToolsUsage').composite as boolean) ?? false;
221+
providerRegistry.allowTools = allowToolsUsage;
222+
219223
// Get the Ai provider settings.
220-
const providerSettings = settings.get('AIproviders')
224+
const providerSettings = setting.get('AIproviders')
221225
.composite as ReadonlyPartialJSONObject;
222226

223227
// Update completer provider.
@@ -239,8 +243,8 @@ const providerRegistryPlugin: JupyterFrontEndPlugin<IAIProviderRegistry> =
239243
}
240244
};
241245

242-
settings.changed.connect(() => updateProvider());
243-
updateProvider();
246+
settings.changed.connect(loadSetting);
247+
loadSetting(settings);
244248
})
245249
.catch(reason => {
246250
console.error(

0 commit comments

Comments
 (0)