@notebook-intelligence/notebook-intelligence 1.3.2 → 1.3.4
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 +15 -7
- package/lib/api.d.ts +1 -0
- package/lib/api.js +3 -0
- package/lib/chat-sidebar.js +26 -4
- package/lib/index.js +13 -1
- package/package.json +1 -1
- package/src/api.ts +4 -0
- package/src/chat-sidebar.tsx +51 -3
- package/src/index.ts +18 -2
- package/style/base.css +12 -0
package/README.md
CHANGED
|
@@ -11,10 +11,16 @@ See blog posts for features and usage.
|
|
|
11
11
|
|
|
12
12
|
### Code generation with inline chat
|
|
13
13
|
|
|
14
|
+
Use the sparkle icon on cell toolbar or the keyboard shortcuts to show the inline chat popover.
|
|
15
|
+
|
|
16
|
+
Keyboard shortcuts: `Ctrl + G` / `Cmd + G` is the shortcut to show the inline chat popover and `Ctrl + Enter` / `Cmd + Enter` is the shortcut to accept the suggestion. Clicking `Escape` key closes the popover.
|
|
17
|
+
|
|
14
18
|

|
|
15
19
|
|
|
16
20
|
### Auto-complete
|
|
17
21
|
|
|
22
|
+
Auto-complete suggestions are shown as you type. Clicking `Tab` key accepts the suggestion. NBI provides auto-complete suggestions in code cells and Python file editors.
|
|
23
|
+
|
|
18
24
|
<img src="media/inline-completion.gif" alt="Auto-complete" width=700 />
|
|
19
25
|
|
|
20
26
|
### Chat interface
|
|
@@ -45,19 +51,21 @@ for the frontend extension.
|
|
|
45
51
|
|
|
46
52
|
### Remembering GitHub Copilot login
|
|
47
53
|
|
|
48
|
-
Notebook Intelligence
|
|
54
|
+
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
55
|
|
|
50
|
-
|
|
56
|
+
> [!CAUTION]
|
|
57
|
+
> 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.
|
|
58
|
+
> 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
59
|
|
|
52
60
|
```bash
|
|
53
|
-
|
|
61
|
+
NBI_GH_ACCESS_TOKEN_PASSWORD=my_custom_password
|
|
54
62
|
```
|
|
55
63
|
|
|
56
|
-
|
|
64
|
+
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
65
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
<img src="media/remember-gh-access-token.png" alt="Remember access token" width=500 />
|
|
67
|
+
|
|
68
|
+
If your stored access token fails to login (due to expiration or other reasons), you will be prompted to relogin on the UI.
|
|
61
69
|
|
|
62
70
|
### Configuration files
|
|
63
71
|
|
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';
|
|
@@ -1123,7 +1123,7 @@ function ConfigurationDialogBodyComponent(props) {
|
|
|
1123
1123
|
const [chatModels, setChatModels] = useState([]);
|
|
1124
1124
|
const [inlineCompletionModels, setInlineCompletionModels] = useState([]);
|
|
1125
1125
|
const handleSaveClick = async () => {
|
|
1126
|
-
|
|
1126
|
+
const config = {
|
|
1127
1127
|
chat_model: {
|
|
1128
1128
|
provider: chatModelProvider,
|
|
1129
1129
|
model: chatModel,
|
|
@@ -1134,7 +1134,12 @@ function ConfigurationDialogBodyComponent(props) {
|
|
|
1134
1134
|
model: inlineCompletionModel,
|
|
1135
1135
|
properties: inlineCompletionModelProperties
|
|
1136
1136
|
}
|
|
1137
|
-
}
|
|
1137
|
+
};
|
|
1138
|
+
if (chatModelProvider === 'github-copilot' ||
|
|
1139
|
+
inlineCompletionModelProvider === 'github-copilot') {
|
|
1140
|
+
config.store_github_access_token = storeGitHubAccessToken;
|
|
1141
|
+
}
|
|
1142
|
+
await NBIAPI.setConfig(config);
|
|
1138
1143
|
props.onSave();
|
|
1139
1144
|
};
|
|
1140
1145
|
const handleRefreshOllamaModelListClick = async () => {
|
|
@@ -1147,6 +1152,7 @@ function ConfigurationDialogBodyComponent(props) {
|
|
|
1147
1152
|
const [chatModelProperties, setChatModelProperties] = useState([]);
|
|
1148
1153
|
const [inlineCompletionModelProperties, setInlineCompletionModelProperties] = useState([]);
|
|
1149
1154
|
const [inlineCompletionModel, setInlineCompletionModel] = useState(nbiConfig.inlineCompletionModel.model);
|
|
1155
|
+
const [storeGitHubAccessToken, setStoreGitHubAccessToken] = useState(nbiConfig.storeGitHubAccessToken);
|
|
1150
1156
|
const updateModelOptionsForProvider = (providerId, modelType) => {
|
|
1151
1157
|
if (modelType === 'chat') {
|
|
1152
1158
|
setChatModelProvider(providerId);
|
|
@@ -1275,7 +1281,23 @@ function ConfigurationDialogBodyComponent(props) {
|
|
|
1275
1281
|
property.name,
|
|
1276
1282
|
" ",
|
|
1277
1283
|
property.optional ? '(optional)' : ''),
|
|
1278
|
-
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"))))))),
|
|
1279
1301
|
React.createElement("div", { className: "config-dialog-footer" },
|
|
1280
1302
|
React.createElement("button", { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", onClick: handleSaveClick },
|
|
1281
1303
|
React.createElement("div", { className: "jp-Dialog-buttonLabel" }, "Save")))));
|
package/lib/index.js
CHANGED
|
@@ -759,7 +759,19 @@ const plugin = {
|
|
|
759
759
|
return editorRect;
|
|
760
760
|
}
|
|
761
761
|
const yOffset = 30;
|
|
762
|
-
const
|
|
762
|
+
const diffViewHeight = 300;
|
|
763
|
+
let top = coords.top - yOffset;
|
|
764
|
+
const height = coords.bottom - coords.top;
|
|
765
|
+
// adjust top to fit in file editor rect
|
|
766
|
+
if (!isCodeCell) {
|
|
767
|
+
if (top + height + diffViewHeight > editorRect.bottom) {
|
|
768
|
+
top = editorRect.bottom - height - diffViewHeight;
|
|
769
|
+
if (top < editorRect.top) {
|
|
770
|
+
top = editorRect.top;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
const rect = new DOMRect(editorRect.left, top, editorRect.right - editorRect.left, height);
|
|
763
775
|
return rect;
|
|
764
776
|
};
|
|
765
777
|
const rect = getRectAtCursor();
|
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
|
|
|
@@ -1823,7 +1824,7 @@ function ConfigurationDialogBodyComponent(props: any) {
|
|
|
1823
1824
|
const [inlineCompletionModels, setInlineCompletionModels] = useState([]);
|
|
1824
1825
|
|
|
1825
1826
|
const handleSaveClick = async () => {
|
|
1826
|
-
|
|
1827
|
+
const config: any = {
|
|
1827
1828
|
chat_model: {
|
|
1828
1829
|
provider: chatModelProvider,
|
|
1829
1830
|
model: chatModel,
|
|
@@ -1834,7 +1835,16 @@ function ConfigurationDialogBodyComponent(props: any) {
|
|
|
1834
1835
|
model: inlineCompletionModel,
|
|
1835
1836
|
properties: inlineCompletionModelProperties
|
|
1836
1837
|
}
|
|
1837
|
-
}
|
|
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);
|
|
1838
1848
|
|
|
1839
1849
|
props.onSave();
|
|
1840
1850
|
};
|
|
@@ -1856,6 +1866,9 @@ function ConfigurationDialogBodyComponent(props: any) {
|
|
|
1856
1866
|
const [inlineCompletionModel, setInlineCompletionModel] = useState(
|
|
1857
1867
|
nbiConfig.inlineCompletionModel.model
|
|
1858
1868
|
);
|
|
1869
|
+
const [storeGitHubAccessToken, setStoreGitHubAccessToken] = useState(
|
|
1870
|
+
nbiConfig.storeGitHubAccessToken
|
|
1871
|
+
);
|
|
1859
1872
|
|
|
1860
1873
|
const updateModelOptionsForProvider = (
|
|
1861
1874
|
providerId: string,
|
|
@@ -2161,6 +2174,41 @@ function ConfigurationDialogBodyComponent(props: any) {
|
|
|
2161
2174
|
</div>
|
|
2162
2175
|
</div>
|
|
2163
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
|
+
)}
|
|
2164
2212
|
</div>
|
|
2165
2213
|
|
|
2166
2214
|
<div className="config-dialog-footer">
|
package/src/index.ts
CHANGED
|
@@ -1018,12 +1018,28 @@ const plugin: JupyterFrontEndPlugin<INotebookIntelligence> = {
|
|
|
1018
1018
|
return editorRect;
|
|
1019
1019
|
}
|
|
1020
1020
|
const yOffset = 30;
|
|
1021
|
+
const diffViewHeight = 300;
|
|
1022
|
+
|
|
1023
|
+
let top = coords.top - yOffset;
|
|
1024
|
+
const height = coords.bottom - coords.top;
|
|
1025
|
+
|
|
1026
|
+
// adjust top to fit in file editor rect
|
|
1027
|
+
if (!isCodeCell) {
|
|
1028
|
+
if (top + height + diffViewHeight > editorRect.bottom) {
|
|
1029
|
+
top = editorRect.bottom - height - diffViewHeight;
|
|
1030
|
+
if (top < editorRect.top) {
|
|
1031
|
+
top = editorRect.top;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1021
1036
|
const rect: DOMRect = new DOMRect(
|
|
1022
1037
|
editorRect.left,
|
|
1023
|
-
|
|
1038
|
+
top,
|
|
1024
1039
|
editorRect.right - editorRect.left,
|
|
1025
|
-
|
|
1040
|
+
height
|
|
1026
1041
|
);
|
|
1042
|
+
|
|
1027
1043
|
return rect;
|
|
1028
1044
|
};
|
|
1029
1045
|
|
package/style/base.css
CHANGED
|
@@ -614,3 +614,15 @@ body[data-jp-theme-light='false'] .inline-popover {
|
|
|
614
614
|
.chat-reasoning-content.expanded .collapsed-icon {
|
|
615
615
|
display: none;
|
|
616
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
|
+
}
|