@notebook-intelligence/notebook-intelligence 1.3.1 → 1.3.3
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.
- package/README.md +9 -7
- package/lib/api.d.ts +1 -0
- package/lib/api.js +3 -0
- package/lib/chat-sidebar.js +29 -5
- package/package.json +1 -1
- package/src/api.ts +4 -0
- package/src/chat-sidebar.tsx +56 -4
- package/style/base.css +16 -0
package/README.md
CHANGED
|
@@ -45,19 +45,21 @@ for the frontend extension.
|
|
|
45
45
|
|
|
46
46
|
### Remembering GitHub Copilot login
|
|
47
47
|
|
|
48
|
-
Notebook Intelligence
|
|
48
|
+
Notebook Intelligence can remember your GitHub Copilot login so that you don't need to re-login after a JupyterLab or system restart. Please be aware of the security implications of using this feature.
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
> [!CAUTION]
|
|
51
|
+
> If you configure NBI to remember your GitHub Copilot login, it will encrypt the token and store into a data file at `~/.jupyter/nbi-data.json`. You should never share this file with others as they can access your tokens.
|
|
52
|
+
> Even though the token is encrypted, it is done so by using a default password and that's why it can be decrypted by others. In order to prevent that you can specify a custom password using the environment variable `NBI_GH_ACCESS_TOKEN_PASSWORD`.
|
|
51
53
|
|
|
52
54
|
```bash
|
|
53
|
-
|
|
55
|
+
NBI_GH_ACCESS_TOKEN_PASSWORD=my_custom_password
|
|
54
56
|
```
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
To let Notebook Intelligence remember your GitHub access token, go to Notebook Intelligence Settings dialog and check the option `Remember my GitHub Copilot access token` as shown below.
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
<img src="media/remember-gh-access-token.png" alt="Remember access token" width=500 />
|
|
61
|
+
|
|
62
|
+
If your stored access token fails to login (due to expiration or other reasons), you will be prompted to relogin on the UI.
|
|
61
63
|
|
|
62
64
|
### Configuration files
|
|
63
65
|
|
package/lib/api.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare class NBIConfig {
|
|
|
17
17
|
get chatModel(): any;
|
|
18
18
|
get inlineCompletionModel(): any;
|
|
19
19
|
get usingGitHubCopilotModel(): boolean;
|
|
20
|
+
get storeGitHubAccessToken(): boolean;
|
|
20
21
|
capabilities: any;
|
|
21
22
|
chatParticipants: IChatParticipant[];
|
|
22
23
|
changed: Signal<this, void>;
|
package/lib/api.js
CHANGED
|
@@ -39,6 +39,9 @@ export class NBIConfig {
|
|
|
39
39
|
return (this.chatModel.provider === GITHUB_COPILOT_PROVIDER_ID ||
|
|
40
40
|
this.inlineCompletionModel.provider === GITHUB_COPILOT_PROVIDER_ID);
|
|
41
41
|
}
|
|
42
|
+
get storeGitHubAccessToken() {
|
|
43
|
+
return this.capabilities.store_github_access_token === true;
|
|
44
|
+
}
|
|
42
45
|
}
|
|
43
46
|
class NBIAPI {
|
|
44
47
|
static async initialize() {
|
package/lib/chat-sidebar.js
CHANGED
|
@@ -9,7 +9,7 @@ import { MarkdownRenderer } from './markdown-renderer';
|
|
|
9
9
|
import copySvgstr from '../style/icons/copy.svg';
|
|
10
10
|
import copilotSvgstr from '../style/icons/copilot.svg';
|
|
11
11
|
import copilotWarningSvgstr from '../style/icons/copilot-warning.svg';
|
|
12
|
-
import { VscSend, VscStopCircle, VscEye, VscEyeClosed, VscTriangleRight, VscTriangleDown } from 'react-icons/vsc';
|
|
12
|
+
import { VscSend, VscStopCircle, VscEye, VscEyeClosed, VscTriangleRight, VscTriangleDown, VscWarning } from 'react-icons/vsc';
|
|
13
13
|
import { extractLLMGeneratedCode, isDarkTheme } from './utils';
|
|
14
14
|
const OPENAI_COMPATIBLE_CHAT_MODEL_ID = 'openai-compatible-chat-model';
|
|
15
15
|
const LITELLM_COMPATIBLE_CHAT_MODEL_ID = 'litellm-compatible-chat-model';
|
|
@@ -151,9 +151,11 @@ function ChatResponse(props) {
|
|
|
151
151
|
};
|
|
152
152
|
const markFormConfirmed = (contentId) => {
|
|
153
153
|
answeredForms.set(contentId, 'confirmed');
|
|
154
|
+
setRenderCount(prev => prev + 1);
|
|
154
155
|
};
|
|
155
156
|
const markFormCanceled = (contentId) => {
|
|
156
157
|
answeredForms.set(contentId, 'canceled');
|
|
158
|
+
setRenderCount(prev => prev + 1);
|
|
157
159
|
};
|
|
158
160
|
const runCommand = (commandId, args) => {
|
|
159
161
|
props.getApp().commands.execute(commandId, args);
|
|
@@ -272,7 +274,7 @@ function ChatResponse(props) {
|
|
|
272
274
|
React.createElement("a", { href: item.content.uri, target: "_blank" }, item.content.title)));
|
|
273
275
|
case ResponseStreamDataType.Progress:
|
|
274
276
|
// show only if no more message available
|
|
275
|
-
return index === groupedContents.length - 1 ? (React.createElement("div", { key: `key-${index}` },
|
|
277
|
+
return index === groupedContents.length - 1 ? (React.createElement("div", { className: "chat-response-progress", key: `key-${index}` },
|
|
276
278
|
"\u2713 ",
|
|
277
279
|
item.content)) : null;
|
|
278
280
|
case ResponseStreamDataType.Confirmation:
|
|
@@ -1121,7 +1123,7 @@ function ConfigurationDialogBodyComponent(props) {
|
|
|
1121
1123
|
const [chatModels, setChatModels] = useState([]);
|
|
1122
1124
|
const [inlineCompletionModels, setInlineCompletionModels] = useState([]);
|
|
1123
1125
|
const handleSaveClick = async () => {
|
|
1124
|
-
|
|
1126
|
+
const config = {
|
|
1125
1127
|
chat_model: {
|
|
1126
1128
|
provider: chatModelProvider,
|
|
1127
1129
|
model: chatModel,
|
|
@@ -1132,7 +1134,12 @@ function ConfigurationDialogBodyComponent(props) {
|
|
|
1132
1134
|
model: inlineCompletionModel,
|
|
1133
1135
|
properties: inlineCompletionModelProperties
|
|
1134
1136
|
}
|
|
1135
|
-
}
|
|
1137
|
+
};
|
|
1138
|
+
if (chatModelProvider === 'github-copilot' ||
|
|
1139
|
+
inlineCompletionModelProvider === 'github-copilot') {
|
|
1140
|
+
config.store_github_access_token = storeGitHubAccessToken;
|
|
1141
|
+
}
|
|
1142
|
+
await NBIAPI.setConfig(config);
|
|
1136
1143
|
props.onSave();
|
|
1137
1144
|
};
|
|
1138
1145
|
const handleRefreshOllamaModelListClick = async () => {
|
|
@@ -1145,6 +1152,7 @@ function ConfigurationDialogBodyComponent(props) {
|
|
|
1145
1152
|
const [chatModelProperties, setChatModelProperties] = useState([]);
|
|
1146
1153
|
const [inlineCompletionModelProperties, setInlineCompletionModelProperties] = useState([]);
|
|
1147
1154
|
const [inlineCompletionModel, setInlineCompletionModel] = useState(nbiConfig.inlineCompletionModel.model);
|
|
1155
|
+
const [storeGitHubAccessToken, setStoreGitHubAccessToken] = useState(nbiConfig.storeGitHubAccessToken);
|
|
1148
1156
|
const updateModelOptionsForProvider = (providerId, modelType) => {
|
|
1149
1157
|
if (modelType === 'chat') {
|
|
1150
1158
|
setChatModelProvider(providerId);
|
|
@@ -1273,7 +1281,23 @@ function ConfigurationDialogBodyComponent(props) {
|
|
|
1273
1281
|
property.name,
|
|
1274
1282
|
" ",
|
|
1275
1283
|
property.optional ? '(optional)' : ''),
|
|
1276
|
-
React.createElement("input", { name: "inline-completion-model-id-input", placeholder: property.description, className: "jp-mod-styled", spellCheck: false, value: property.value, onChange: event => onModelPropertyChange('inline-completion', property.id, event.target.value) }))))))))
|
|
1284
|
+
React.createElement("input", { name: "inline-completion-model-id-input", placeholder: property.description, className: "jp-mod-styled", spellCheck: false, value: property.value, onChange: event => onModelPropertyChange('inline-completion', property.id, event.target.value) })))))))),
|
|
1285
|
+
(chatModelProvider === 'github-copilot' ||
|
|
1286
|
+
inlineCompletionModelProvider === 'github-copilot') && (React.createElement("div", { className: "model-config-section" },
|
|
1287
|
+
React.createElement("div", { className: "model-config-section-header access-token-config-header" },
|
|
1288
|
+
"GitHub Copilot login",
|
|
1289
|
+
' ',
|
|
1290
|
+
React.createElement("a", { href: "https://github.com/notebook-intelligence/notebook-intelligence/blob/main/README.md#remembering-github-copilot-login", target: "_blank" },
|
|
1291
|
+
' ',
|
|
1292
|
+
React.createElement(VscWarning, { className: "access-token-warning", title: "Click to learn more about security implications" }))),
|
|
1293
|
+
React.createElement("div", { className: "model-config-section-body" },
|
|
1294
|
+
React.createElement("div", { className: "model-config-section-row" },
|
|
1295
|
+
React.createElement("div", { className: "model-config-section-column" },
|
|
1296
|
+
React.createElement("label", null,
|
|
1297
|
+
React.createElement("input", { type: "checkbox", checked: storeGitHubAccessToken, onChange: event => {
|
|
1298
|
+
setStoreGitHubAccessToken(event.target.checked);
|
|
1299
|
+
} }),
|
|
1300
|
+
"Remember my GitHub Copilot access token"))))))),
|
|
1277
1301
|
React.createElement("div", { className: "config-dialog-footer" },
|
|
1278
1302
|
React.createElement("button", { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", onClick: handleSaveClick },
|
|
1279
1303
|
React.createElement("div", { className: "jp-Dialog-buttonLabel" }, "Save")))));
|
package/package.json
CHANGED
package/src/api.ts
CHANGED
package/src/chat-sidebar.tsx
CHANGED
|
@@ -41,7 +41,8 @@ import {
|
|
|
41
41
|
VscEye,
|
|
42
42
|
VscEyeClosed,
|
|
43
43
|
VscTriangleRight,
|
|
44
|
-
VscTriangleDown
|
|
44
|
+
VscTriangleDown,
|
|
45
|
+
VscWarning
|
|
45
46
|
} from 'react-icons/vsc';
|
|
46
47
|
import { extractLLMGeneratedCode, isDarkTheme } from './utils';
|
|
47
48
|
|
|
@@ -314,9 +315,11 @@ function ChatResponse(props: any) {
|
|
|
314
315
|
|
|
315
316
|
const markFormConfirmed = (contentId: string) => {
|
|
316
317
|
answeredForms.set(contentId, 'confirmed');
|
|
318
|
+
setRenderCount(prev => prev + 1);
|
|
317
319
|
};
|
|
318
320
|
const markFormCanceled = (contentId: string) => {
|
|
319
321
|
answeredForms.set(contentId, 'canceled');
|
|
322
|
+
setRenderCount(prev => prev + 1);
|
|
320
323
|
};
|
|
321
324
|
|
|
322
325
|
const runCommand = (commandId: string, args: any) => {
|
|
@@ -517,7 +520,9 @@ function ChatResponse(props: any) {
|
|
|
517
520
|
case ResponseStreamDataType.Progress:
|
|
518
521
|
// show only if no more message available
|
|
519
522
|
return index === groupedContents.length - 1 ? (
|
|
520
|
-
<div key={`key-${index}`}
|
|
523
|
+
<div className="chat-response-progress" key={`key-${index}`}>
|
|
524
|
+
✓ {item.content}
|
|
525
|
+
</div>
|
|
521
526
|
) : null;
|
|
522
527
|
case ResponseStreamDataType.Confirmation:
|
|
523
528
|
return answeredForms.get(item.id) ===
|
|
@@ -1819,7 +1824,7 @@ function ConfigurationDialogBodyComponent(props: any) {
|
|
|
1819
1824
|
const [inlineCompletionModels, setInlineCompletionModels] = useState([]);
|
|
1820
1825
|
|
|
1821
1826
|
const handleSaveClick = async () => {
|
|
1822
|
-
|
|
1827
|
+
const config: any = {
|
|
1823
1828
|
chat_model: {
|
|
1824
1829
|
provider: chatModelProvider,
|
|
1825
1830
|
model: chatModel,
|
|
@@ -1830,7 +1835,16 @@ function ConfigurationDialogBodyComponent(props: any) {
|
|
|
1830
1835
|
model: inlineCompletionModel,
|
|
1831
1836
|
properties: inlineCompletionModelProperties
|
|
1832
1837
|
}
|
|
1833
|
-
}
|
|
1838
|
+
};
|
|
1839
|
+
|
|
1840
|
+
if (
|
|
1841
|
+
chatModelProvider === 'github-copilot' ||
|
|
1842
|
+
inlineCompletionModelProvider === 'github-copilot'
|
|
1843
|
+
) {
|
|
1844
|
+
config.store_github_access_token = storeGitHubAccessToken;
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
await NBIAPI.setConfig(config);
|
|
1834
1848
|
|
|
1835
1849
|
props.onSave();
|
|
1836
1850
|
};
|
|
@@ -1852,6 +1866,9 @@ function ConfigurationDialogBodyComponent(props: any) {
|
|
|
1852
1866
|
const [inlineCompletionModel, setInlineCompletionModel] = useState(
|
|
1853
1867
|
nbiConfig.inlineCompletionModel.model
|
|
1854
1868
|
);
|
|
1869
|
+
const [storeGitHubAccessToken, setStoreGitHubAccessToken] = useState(
|
|
1870
|
+
nbiConfig.storeGitHubAccessToken
|
|
1871
|
+
);
|
|
1855
1872
|
|
|
1856
1873
|
const updateModelOptionsForProvider = (
|
|
1857
1874
|
providerId: string,
|
|
@@ -2157,6 +2174,41 @@ function ConfigurationDialogBodyComponent(props: any) {
|
|
|
2157
2174
|
</div>
|
|
2158
2175
|
</div>
|
|
2159
2176
|
</div>
|
|
2177
|
+
|
|
2178
|
+
{(chatModelProvider === 'github-copilot' ||
|
|
2179
|
+
inlineCompletionModelProvider === 'github-copilot') && (
|
|
2180
|
+
<div className="model-config-section">
|
|
2181
|
+
<div className="model-config-section-header access-token-config-header">
|
|
2182
|
+
GitHub Copilot login{' '}
|
|
2183
|
+
<a
|
|
2184
|
+
href="https://github.com/notebook-intelligence/notebook-intelligence/blob/main/README.md#remembering-github-copilot-login"
|
|
2185
|
+
target="_blank"
|
|
2186
|
+
>
|
|
2187
|
+
{' '}
|
|
2188
|
+
<VscWarning
|
|
2189
|
+
className="access-token-warning"
|
|
2190
|
+
title="Click to learn more about security implications"
|
|
2191
|
+
/>
|
|
2192
|
+
</a>
|
|
2193
|
+
</div>
|
|
2194
|
+
<div className="model-config-section-body">
|
|
2195
|
+
<div className="model-config-section-row">
|
|
2196
|
+
<div className="model-config-section-column">
|
|
2197
|
+
<label>
|
|
2198
|
+
<input
|
|
2199
|
+
type="checkbox"
|
|
2200
|
+
checked={storeGitHubAccessToken}
|
|
2201
|
+
onChange={event => {
|
|
2202
|
+
setStoreGitHubAccessToken(event.target.checked);
|
|
2203
|
+
}}
|
|
2204
|
+
/>
|
|
2205
|
+
Remember my GitHub Copilot access token
|
|
2206
|
+
</label>
|
|
2207
|
+
</div>
|
|
2208
|
+
</div>
|
|
2209
|
+
</div>
|
|
2210
|
+
</div>
|
|
2211
|
+
)}
|
|
2160
2212
|
</div>
|
|
2161
2213
|
|
|
2162
2214
|
<div className="config-dialog-footer">
|
package/style/base.css
CHANGED
|
@@ -275,6 +275,10 @@ pre:has(.code-block-header) {
|
|
|
275
275
|
margin: 5px 0;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
.chat-response-progress {
|
|
279
|
+
margin: 5px 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
278
282
|
.chat-confirmation-form {
|
|
279
283
|
border: 1px solid var(--jp-border-color1);
|
|
280
284
|
padding: 5px;
|
|
@@ -610,3 +614,15 @@ body[data-jp-theme-light='false'] .inline-popover {
|
|
|
610
614
|
.chat-reasoning-content.expanded .collapsed-icon {
|
|
611
615
|
display: none;
|
|
612
616
|
}
|
|
617
|
+
|
|
618
|
+
.access-token-config-header {
|
|
619
|
+
display: flex;
|
|
620
|
+
align-items: center;
|
|
621
|
+
gap: 10px;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
svg.access-token-warning {
|
|
625
|
+
color: var(--jp-warn-color0);
|
|
626
|
+
width: 18px;
|
|
627
|
+
height: 18px;
|
|
628
|
+
}
|