@datalayer/core 0.0.19 → 0.0.20

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/lib/App.js +0 -5
  2. package/lib/components/auth/Login.js +0 -5
  3. package/lib/components/auth/index.js +1 -6
  4. package/lib/components/index.d.ts +0 -1
  5. package/lib/components/index.js +0 -1
  6. package/lib/components/toolbars/AssignmentEditorToolbar.js +9 -7
  7. package/lib/examples/CellExample.js +4 -3
  8. package/lib/examples/NotebookExample.js +2 -7
  9. package/lib/hooks/index.d.ts +0 -2
  10. package/lib/hooks/index.js +0 -2
  11. package/lib/hooks/useCache.d.ts +15 -1
  12. package/lib/hooks/useCache.js +87 -69
  13. package/lib/index.d.ts +1 -0
  14. package/lib/index.js +3 -1
  15. package/lib/main.js +4 -1
  16. package/lib/models/index.d.ts +0 -1
  17. package/lib/models/index.js +0 -1
  18. package/lib/state/substates/index.d.ts +0 -1
  19. package/lib/state/substates/index.js +0 -1
  20. package/lib/utils/cli/index.js +0 -5
  21. package/lib/utils/cli/query.js +0 -5
  22. package/lib/views/datasources/DatasourceDetail.d.ts +2 -0
  23. package/lib/views/datasources/DatasourceDetail.js +91 -0
  24. package/lib/views/datasources/DatasourceNew.d.ts +2 -0
  25. package/lib/views/datasources/DatasourceNew.js +118 -0
  26. package/lib/views/datasources/Datasources.d.ts +2 -0
  27. package/lib/views/datasources/Datasources.js +49 -0
  28. package/lib/views/datasources/index.d.ts +3 -0
  29. package/lib/views/datasources/index.js +7 -0
  30. package/lib/views/iam-tokens/IAMTokenEdit.d.ts +2 -0
  31. package/lib/views/iam-tokens/IAMTokenEdit.js +86 -0
  32. package/lib/views/iam-tokens/IAMTokenNew.d.ts +2 -0
  33. package/lib/views/iam-tokens/IAMTokenNew.js +118 -0
  34. package/lib/views/iam-tokens/IAMTokens.d.ts +2 -0
  35. package/lib/views/iam-tokens/IAMTokens.js +53 -0
  36. package/lib/views/iam-tokens/Tokens.d.ts +2 -0
  37. package/lib/views/iam-tokens/Tokens.js +53 -0
  38. package/lib/views/iam-tokens/index.d.ts +3 -0
  39. package/lib/views/iam-tokens/index.js +7 -0
  40. package/lib/views/index.d.ts +1 -0
  41. package/lib/views/secrets/SecretEdit.d.ts +2 -0
  42. package/lib/views/secrets/SecretEdit.js +149 -0
  43. package/lib/views/secrets/SecretNew.d.ts +2 -0
  44. package/lib/views/secrets/SecretNew.js +99 -0
  45. package/lib/views/secrets/Secrets.d.ts +2 -0
  46. package/lib/views/secrets/Secrets.js +48 -0
  47. package/lib/views/secrets/index.d.ts +3 -0
  48. package/lib/views/secrets/index.js +7 -0
  49. package/package.json +9 -12
  50. package/lib/components/chat/ChatComponent.d.ts +0 -4
  51. package/lib/components/chat/ChatComponent.js +0 -143
  52. package/lib/components/chat/MessagePart.d.ts +0 -11
  53. package/lib/components/chat/MessagePart.js +0 -23
  54. package/lib/components/chat/display/DynamicToolPart.d.ts +0 -6
  55. package/lib/components/chat/display/DynamicToolPart.js +0 -5
  56. package/lib/components/chat/display/ReasoningPart.d.ts +0 -6
  57. package/lib/components/chat/display/ReasoningPart.js +0 -58
  58. package/lib/components/chat/display/TextPart.d.ts +0 -9
  59. package/lib/components/chat/display/TextPart.js +0 -93
  60. package/lib/components/chat/display/ToolPart.d.ts +0 -6
  61. package/lib/components/chat/display/ToolPart.js +0 -148
  62. package/lib/components/chat/display/index.d.ts +0 -4
  63. package/lib/components/chat/display/index.js +0 -13
  64. package/lib/components/chat/handler.d.ts +0 -8
  65. package/lib/components/chat/handler.js +0 -43
  66. package/lib/components/chat/index.d.ts +0 -4
  67. package/lib/components/chat/index.js +0 -13
  68. package/lib/hooks/useAIAgents.d.ts +0 -13
  69. package/lib/hooks/useAIAgents.js +0 -72
  70. package/lib/hooks/useAIJupyterChat.d.ts +0 -36
  71. package/lib/hooks/useAIJupyterChat.js +0 -53
  72. package/lib/hooks/useNotebookAIAgent.d.ts +0 -8
  73. package/lib/hooks/useNotebookAIAgent.js +0 -56
  74. package/lib/models/AIAgent.d.ts +0 -17
  75. package/lib/state/substates/AIAgentState.d.ts +0 -11
  76. package/lib/state/substates/AIAgentState.js +0 -42
  77. package/lib/tools/adapters/agui/AgUIToolAdapter.d.ts +0 -75
  78. package/lib/tools/adapters/agui/AgUIToolAdapter.js +0 -244
  79. package/lib/tools/adapters/agui/index.d.ts +0 -10
  80. package/lib/tools/adapters/agui/index.js +0 -19
  81. package/lib/tools/adapters/agui/lexicalHooks.d.ts +0 -27
  82. package/lib/tools/adapters/agui/lexicalHooks.js +0 -64
  83. package/lib/tools/adapters/agui/notebookHooks.d.ts +0 -27
  84. package/lib/tools/adapters/agui/notebookHooks.js +0 -61
  85. package/lib/tools/index.d.ts +0 -6
  86. package/lib/tools/index.js +0 -18
  87. package/lib/{models/AIAgent.js → views/index.js} +1 -1
@@ -0,0 +1,2 @@
1
+ export declare const SecretEdit: () => import("react/jsx-runtime").JSX.Element;
2
+ export default SecretEdit;
@@ -0,0 +1,149 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2023-2025 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ import { useState, useEffect } from 'react';
7
+ import { useParams } from 'react-router-dom';
8
+ import { PageHeader, Heading, Text, Button, TextInput, FormControl, Textarea, Label, } from '@primer/react';
9
+ import { Box } from '@datalayer/primer-addons';
10
+ import { EyeIcon, EyeClosedIcon } from '@primer/octicons-react';
11
+ import { BoringAvatar } from '../../components/avatars';
12
+ import { useCache, useNavigate, useToast } from '../../hooks';
13
+ import { useRunStore } from '../../state';
14
+ export const SecretEdit = () => {
15
+ const { secretId } = useParams();
16
+ const runStore = useRunStore();
17
+ const navigate = useNavigate();
18
+ const { enqueueToast } = useToast();
19
+ const { useUpdateSecret, useSecret, useDeleteSecret } = useCache();
20
+ const updateSecretMutation = useUpdateSecret();
21
+ const deleteSecretMutation = useDeleteSecret();
22
+ const secretQuery = useSecret(secretId, {
23
+ refetchOnMount: true,
24
+ });
25
+ const [secret, setSecret] = useState();
26
+ const [formValues, setFormValues] = useState({
27
+ name: '',
28
+ nameConfirm: '',
29
+ description: '',
30
+ value: '',
31
+ });
32
+ const [validationResult, setValidationResult] = useState({
33
+ name: undefined,
34
+ nameConfirm: undefined,
35
+ description: undefined,
36
+ value: undefined,
37
+ });
38
+ const [passwordVisible, setPasswordVisible] = useState(false);
39
+ useEffect(() => {
40
+ if (secretQuery.data) {
41
+ const secret = secretQuery.data;
42
+ setSecret(secret);
43
+ setFormValues({
44
+ name: secret.name || '',
45
+ nameConfirm: '',
46
+ description: secret.description || '',
47
+ value: secret.value ? atob(secret.value) : '',
48
+ });
49
+ }
50
+ }, [secretQuery.data]);
51
+ const secretNameChanged = (event) => {
52
+ setFormValues(prevFormValues => ({
53
+ ...prevFormValues,
54
+ name: event.target.value,
55
+ }));
56
+ };
57
+ const secretNameConfirmChanged = (event) => {
58
+ setFormValues(prevFormValues => ({
59
+ ...prevFormValues,
60
+ nameConfirm: event.target.value,
61
+ }));
62
+ };
63
+ const secretDescriptionChanged = (event) => {
64
+ setFormValues(prevFormValues => ({
65
+ ...prevFormValues,
66
+ description: event.target.value,
67
+ }));
68
+ };
69
+ const secretValueChanged = (event) => {
70
+ setFormValues(prevFormValues => ({
71
+ ...prevFormValues,
72
+ value: event.target.value,
73
+ }));
74
+ };
75
+ useEffect(() => {
76
+ setValidationResult({
77
+ ...validationResult,
78
+ name: formValues.name === undefined
79
+ ? undefined
80
+ : formValues.name.length > 2
81
+ ? true
82
+ : false,
83
+ nameConfirm: formValues.nameConfirm === secret?.name ? true : false,
84
+ description: formValues.description === undefined
85
+ ? undefined
86
+ : formValues.description.length > 2
87
+ ? true
88
+ : false,
89
+ value: formValues.value === undefined
90
+ ? undefined
91
+ : formValues.value.length > 0 && formValues.value.length < 4096
92
+ ? true
93
+ : false,
94
+ });
95
+ }, [formValues]);
96
+ const submitUpdate = async () => {
97
+ runStore.layout().showBackdrop('Updating the secret...');
98
+ secret.name = formValues.name;
99
+ secret.description = formValues.description;
100
+ secret.value = btoa(formValues.value);
101
+ updateSecretMutation.mutate(secret, {
102
+ onSuccess: (resp) => {
103
+ if (resp.success) {
104
+ enqueueToast('The secret is successfully updated.', {
105
+ variant: 'success',
106
+ });
107
+ setSecret(secret);
108
+ }
109
+ },
110
+ onSettled: () => {
111
+ runStore.layout().hideBackdrop();
112
+ },
113
+ });
114
+ };
115
+ const submitDelete = async () => {
116
+ runStore.layout().showBackdrop('Deleting the secret...');
117
+ deleteSecretMutation.mutate(secret.id, {
118
+ onSuccess: (resp) => {
119
+ if (resp.success) {
120
+ enqueueToast('The secret is successfully deleted.', {
121
+ variant: 'success',
122
+ });
123
+ navigate(`/settings/iam/secrets`);
124
+ }
125
+ },
126
+ onSettled: () => {
127
+ runStore.layout().hideBackdrop();
128
+ },
129
+ });
130
+ };
131
+ return (_jsxs(_Fragment, { children: [_jsx(PageHeader, { children: _jsx(Heading, { sx: { fontSize: 3 }, children: "Secret" }) }), _jsxs(Box, { display: "flex", children: [_jsxs(Box, { children: [_jsx(BoringAvatar, { displayName: secret?.name, size: 100, style: { paddingRight: 10 } }), _jsx(Text, { as: "h2", sx: { paddingTop: 3 }, children: secret?.name }), _jsx(Box, { mt: 3, children: _jsx(Label, { size: "large", children: secret?.variant }) })] }), _jsxs(Box, { ml: 10, children: [_jsxs(Box, { sx: { label: { marginTop: 2 } }, children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Name" }), _jsx(TextInput, { block: true, value: formValues.name, onChange: secretNameChanged }), validationResult.name === false && (_jsx(FormControl.Validation, { variant: "error", children: "Name must have more than 2 characters." }))] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Description" }), _jsx(Textarea, { block: true, value: formValues.description, onChange: secretDescriptionChanged, rows: 5 }), validationResult.description === false && (_jsx(FormControl.Validation, { variant: "error", children: "Description must have more than 2 characters." }))] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Value" }), _jsx(TextInput, { placeholder: "Value", monospace: true, size: "large", contrast: !passwordVisible, disabled: !passwordVisible, onChange: secretValueChanged, type: passwordVisible ? 'text' : 'password', value: formValues.value, trailingAction: _jsx(TextInput.Action, { onClick: () => {
132
+ setPasswordVisible(!passwordVisible);
133
+ }, icon: passwordVisible ? EyeClosedIcon : EyeIcon, "aria-label": passwordVisible ? 'Hide secret' : 'Reveal secret', sx: { color: 'var(--fgColor-muted)' } }), sx: { overflow: 'visible' } }), validationResult.value === false && (_jsx(FormControl.Validation, { variant: "error", children: "Value must have more than 1 and less than 4096 characters." }))] }), _jsx(Box, { sx: { marginTop: 3 }, children: _jsx(Button, { variant: "primary", disabled: !validationResult.name || !validationResult.description, onClick: submitUpdate, children: "Update secret" }) })] }), _jsxs(Box, { sx: { marginTop: 3 }, children: [_jsx(Heading, { as: "h2", sx: {
134
+ fontSize: 4,
135
+ fontWeight: 'normal',
136
+ color: 'danger.fg',
137
+ mb: 2,
138
+ }, children: "Danger zone" }), _jsxs(Box, { sx: {
139
+ border: '1px solid',
140
+ borderColor: 'danger.emphasis',
141
+ borderRadius: 2,
142
+ p: 3,
143
+ display: 'flex',
144
+ alignItems: 'center',
145
+ justifyContent: 'space-between',
146
+ gap: 3,
147
+ }, children: [_jsxs(Box, { sx: { display: 'grid', gap: 1 }, children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold', color: 'danger.fg' }, children: "Confirm the secret name to delete" }), _jsx(FormControl, { children: _jsx(TextInput, { block: true, value: formValues.nameConfirm, onChange: secretNameConfirmChanged }) }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "This operation is not reversible." })] }), _jsx(Button, { variant: "danger", disabled: !validationResult.nameConfirm, onClick: submitDelete, children: "Delete secret" })] })] })] })] })] }));
148
+ };
149
+ export default SecretEdit;
@@ -0,0 +1,2 @@
1
+ export declare const SecretNew: () => import("react/jsx-runtime").JSX.Element;
2
+ export default SecretNew;
@@ -0,0 +1,99 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2023-2025 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ import { useEffect, useState } from 'react';
7
+ import { PageHeader, FormControl, Button, TextInput, Textarea, Select, } from '@primer/react';
8
+ import { Box } from '@datalayer/primer-addons';
9
+ import { useCache, useNavigate, useToast } from '../../hooks';
10
+ import { useRunStore } from '../../state';
11
+ export const SecretNew = () => {
12
+ const runStore = useRunStore();
13
+ const navigate = useNavigate();
14
+ const { useCreateSecret } = useCache();
15
+ const createSecretMutation = useCreateSecret();
16
+ const { enqueueToast } = useToast();
17
+ const [formValues, setFormValues] = useState({
18
+ variant: 'generic',
19
+ value: undefined,
20
+ name: undefined,
21
+ description: undefined,
22
+ });
23
+ const [validationResult, setValidationResult] = useState({
24
+ variant: undefined,
25
+ value: undefined,
26
+ name: undefined,
27
+ description: undefined,
28
+ });
29
+ const secretVariantChanged = (event) => {
30
+ setFormValues(prevFormValues => ({
31
+ ...prevFormValues,
32
+ variant: event.target.value,
33
+ }));
34
+ };
35
+ const secretValueChanged = (event) => {
36
+ setFormValues(prevFormValues => ({
37
+ ...prevFormValues,
38
+ value: event.target.value,
39
+ }));
40
+ };
41
+ const secretNameChanged = (event) => {
42
+ setFormValues(prevFormValues => ({
43
+ ...prevFormValues,
44
+ name: event.target.value,
45
+ }));
46
+ };
47
+ const secretDescriptionChanged = (event) => {
48
+ setFormValues(prevFormValues => ({
49
+ ...prevFormValues,
50
+ description: event.target.value,
51
+ }));
52
+ };
53
+ useEffect(() => {
54
+ setValidationResult({
55
+ ...validationResult,
56
+ name: formValues.name === undefined
57
+ ? undefined
58
+ : formValues.name.length > 2
59
+ ? true
60
+ : false,
61
+ description: formValues.description === undefined
62
+ ? undefined
63
+ : formValues.description.length > 2
64
+ ? true
65
+ : false,
66
+ value: formValues.value === undefined
67
+ ? undefined
68
+ : formValues.value.length > 0 && formValues.value.length < 4096
69
+ ? true
70
+ : false,
71
+ });
72
+ }, [formValues]);
73
+ const submitCreate = () => {
74
+ runStore.layout().showBackdrop('Creating an secret...');
75
+ createSecretMutation.mutate({
76
+ variant: formValues.variant,
77
+ name: formValues.name,
78
+ description: formValues.description,
79
+ value: btoa(formValues.value),
80
+ }, {
81
+ onSuccess: (resp) => {
82
+ if (resp.success) {
83
+ enqueueToast(resp.message, { variant: 'success' });
84
+ navigate(`/settings/iam/secrets`);
85
+ }
86
+ },
87
+ onSettled: () => {
88
+ runStore.layout().hideBackdrop();
89
+ },
90
+ });
91
+ };
92
+ return (_jsxs(Box, { children: [_jsx(PageHeader, { children: _jsx(PageHeader.TitleArea, { variant: "large", children: _jsx(PageHeader.Title, { children: "New Secret" }) }) }), _jsx(Box, { display: "grid", gridTemplateColumns: "1fr 1fr", sx: { gap: 3 }, children: _jsx(Box, { children: _jsxs(Box, { sx: { label: { marginTop: 2 } }, children: [_jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Secret type" }), _jsxs(Select, { name: "type", value: formValues.variant, onChange: secretVariantChanged, children: [_jsx(Select.Option, { value: "generic", children: "Generic" }), _jsx(Select.Option, { value: "password", children: "Password" }), _jsx(Select.Option, { value: "key", children: "Key" }), _jsx(Select.Option, { value: "token", children: "Token" })] }), _jsx(FormControl.Caption, { children: "Pick the most appropriate secret type." })] }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Name" }), _jsx(TextInput, { block: true, value: formValues.name, onChange: secretNameChanged, autoFocus: true }), _jsx(FormControl.Caption, { children: "Hint: The secret name is a short name that identifies in a unique way your secret." }), validationResult.name === false && (_jsx(FormControl.Validation, { variant: "error", children: "Name length must be between 2 and 32 characters." }))] }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Description" }), _jsx(Textarea, { block: true, value: formValues.description, onChange: secretDescriptionChanged, rows: 3 }), validationResult.description === false && (_jsx(FormControl.Validation, { variant: "error", children: "Description must have more than 2 characters." }))] }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Value" }), _jsx(Textarea, { block: true, value: formValues.value, onChange: secretValueChanged, rows: 5 }), validationResult.value === false && (_jsx(FormControl.Validation, { variant: "error", children: "Value must have more than 1 and less than 4096 characters." }))] }), _jsx(Button, { variant: "primary", disabled: !validationResult.value ||
93
+ !validationResult.name ||
94
+ !validationResult.description, sx: { marginTop: 2 }, onClick: e => {
95
+ e.preventDefault();
96
+ submitCreate();
97
+ }, children: "Create a secret" })] }) }) })] }));
98
+ };
99
+ export default SecretNew;
@@ -0,0 +1,2 @@
1
+ export declare const Secrets: () => import("react/jsx-runtime").JSX.Element;
2
+ export default Secrets;
@@ -0,0 +1,48 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2023-2025 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ import { useState, useEffect } from 'react';
7
+ import { PageLayout, Button, IconButton, Text, Label } from '@primer/react';
8
+ import { Blankslate, PageHeader, Table, DataTable, } from '@primer/react/experimental';
9
+ import { Box } from '@datalayer/primer-addons';
10
+ import { EditIcon } from '@datalayer/icons-react';
11
+ import { useCache, useNavigate } from '../../hooks';
12
+ const SecretsTable = () => {
13
+ const { useSecrets } = useCache();
14
+ const secretsQuery = useSecrets();
15
+ const navigate = useNavigate();
16
+ const [secrets, setSecrets] = useState([]);
17
+ useEffect(() => {
18
+ if (secretsQuery.data) {
19
+ setSecrets(secretsQuery.data || []);
20
+ }
21
+ }, [secretsQuery.data]);
22
+ return secrets.length === 0 ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Heading, { children: "Secrets" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "No Secrets found." }) })] })) : (_jsxs(Table.Container, { children: [_jsx(Table.Title, { as: "h2", id: "secrets", children: "Secrets" }), _jsx(DataTable, { "aria-labelledby": "secrets", "aria-describedby": "secrets-subtitle", data: secrets, columns: [
23
+ {
24
+ header: 'Type',
25
+ field: 'variant',
26
+ renderCell: secret => _jsx(Label, { children: secret.variant }),
27
+ },
28
+ {
29
+ header: 'Name',
30
+ field: 'name',
31
+ rowHeader: true,
32
+ },
33
+ {
34
+ header: 'Description',
35
+ field: 'description',
36
+ },
37
+ {
38
+ header: '',
39
+ field: 'id',
40
+ renderCell: secret => (_jsx(IconButton, { icon: EditIcon, "aria-label": "Edit", size: "small", variant: "invisible", onClick: e => navigate(`${secret.id}`, e) })),
41
+ },
42
+ ] })] }));
43
+ };
44
+ export const Secrets = () => {
45
+ const navigate = useNavigate();
46
+ return (_jsxs(PageLayout, { containerWidth: "full", padding: "normal", style: { overflow: 'visible', minHeight: 'calc(100vh - 45px)' }, children: [_jsx(PageLayout.Header, { children: _jsxs(PageHeader, { children: [_jsx(PageHeader.TitleArea, { variant: "large", children: _jsx(PageHeader.Title, { children: "Secrets" }) }), _jsx(PageHeader.Actions, { children: _jsx(Button, { size: "small", variant: "primary", onClick: e => navigate('/new/secret', e), children: "New secret" }) })] }) }), _jsx(PageLayout.Content, { children: _jsx(Box, { children: _jsx(SecretsTable, {}) }) })] }));
47
+ };
48
+ export default Secrets;
@@ -0,0 +1,3 @@
1
+ export * from './SecretEdit';
2
+ export * from './SecretNew';
3
+ export * from './Secrets';
@@ -0,0 +1,7 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ export * from './SecretEdit';
6
+ export * from './SecretNew';
7
+ export * from './Secrets';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/core",
3
- "version": "0.0.19",
3
+ "version": "0.0.20",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",
@@ -85,12 +85,12 @@
85
85
  "watch:lib:res": "gulp resources-to-lib-watch",
86
86
  "watch:lib:src": "tsc -b -w",
87
87
  "type-check:watch": "tsc -b -w --noEmit",
88
- "examples": "vite --config vite.examples.config.ts",
89
- "examples:chat": "run-p jupyter:start example:chat:vite",
90
- "examples:chat:vite": "EXAMPLE=ChatExample vite --config vite.examples.config.ts",
88
+ "examples": "run-p jupyter:start examples:vite",
89
+ "examples:vite": "VITE_DATALAYER_RUN_URL=http://localhost:8888 vite --config vite.examples.config.ts",
91
90
  "examples:nextjs": "npm run dev --workspace=nextjs-notebook-example",
92
91
  "jupyter:start": "./dev/sh/start-jupyter-server.sh",
93
92
  "prepare": "husky",
93
+ "postinstall": "bash scripts/apply-patches.sh",
94
94
  "kill": "./dev/sh/kill.sh || true",
95
95
  "sync:jupyter": "bash scripts/sync-jupyter.sh",
96
96
  "sync:jupyter:watch": "bash scripts/sync-jupyter.sh --watch",
@@ -100,14 +100,12 @@
100
100
  "rebuild:fresh": "npm run create:patches && npm install && npm run build && npm run clean:cache"
101
101
  },
102
102
  "dependencies": {
103
- "@ai-sdk/react": "^2.0.34",
104
- "@copilotkit/react-core": "^1.10.6",
105
- "@copilotkit/react-ui": "^1.10.6",
106
103
  "@datalayer/icons-react": "^1.0.6",
107
- "@datalayer/jupyter-lexical": "^1.0.6",
108
- "@datalayer/jupyter-react": "^1.1.8",
104
+ "@datalayer/jupyter-lexical": "^1.0.7",
105
+ "@datalayer/jupyter-react": "^2.0.0",
109
106
  "@datalayer/primer-addons": "^1.0.4",
110
107
  "@datalayer/primer-rjsf": "^1.0.1",
108
+ "@fluentui/react": "^8.125.3",
111
109
  "@jupyter-widgets/base-manager": "^1.0.12",
112
110
  "@jupyter-widgets/schema": "^0.5.6",
113
111
  "@jupyterlab/apputils": "^4.6.0",
@@ -119,7 +117,6 @@
119
117
  "@jupyterlab/services": "^7.0.0",
120
118
  "@jupyterlab/translation": "^4.5.0",
121
119
  "@jupyterlab/ui-components": "^4.5.0",
122
- "@jupyterlite/javascript-kernel-extension": "^0.3.0",
123
120
  "@lumino/commands": "^2.3.3",
124
121
  "@lumino/coreutils": "^2.2.2",
125
122
  "@lumino/datagrid": "^2.5.3",
@@ -144,9 +141,9 @@
144
141
  "ansi-to-html": "^0.7.2",
145
142
  "axios": "^1.7.7",
146
143
  "boring-avatars": "^2.0.1",
147
- "buffer": "^6.0.3",
148
144
  "date-fns": "^2.29.3",
149
145
  "deepmerge": "^4.3.1",
146
+ "diff": "^8.0.2",
150
147
  "echarts": "^5.5.0",
151
148
  "echarts-for-react": "^3.0.2",
152
149
  "fuse.js": "^7.0.0",
@@ -174,6 +171,7 @@
174
171
  "uuid": "^13.0.0",
175
172
  "validator": "^13.7.0",
176
173
  "zod": "^4.1.13",
174
+ "zod-to-json-schema": "^3.25.0",
177
175
  "zustand": "^4.4.1"
178
176
  },
179
177
  "peerDependencies": {
@@ -203,7 +201,6 @@
203
201
  "@vitest/coverage-v8": "^3.2.4",
204
202
  "abort-controller": "^3.0.0",
205
203
  "autoprefixer": "^10.4.21",
206
- "buffer": "^6.0.3",
207
204
  "crypto-browserify": "^3.12.1",
208
205
  "dotenv": "^17.2.2",
209
206
  "eslint": "^9.29.0",
@@ -1,4 +0,0 @@
1
- /**
2
- * Main Chat component using Primer React
3
- */
4
- export declare const ChatComponent: React.FC;
@@ -1,143 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /*
3
- * Copyright (c) 2023-2025 Datalayer, Inc.
4
- * Distributed under the terms of the Modified BSD License.
5
- */
6
- /*
7
- * Copyright (c) 2024-2025 Datalayer, Inc.
8
- *
9
- * BSD 3-Clause License
10
- */
11
- import { useState, useEffect, useMemo, useRef } from 'react';
12
- import { useQuery } from '@tanstack/react-query';
13
- import { Box, Button, IconButton, Textarea, FormControl, Spinner, ActionMenu, ActionList, Text, } from '@primer/react';
14
- import { ToolsIcon, ArrowUpIcon, ArrowDownIcon, AiModelIcon, } from '@primer/octicons-react';
15
- import { useAIJupyterChat } from '../../hooks/useAIJupyterChat';
16
- import { requestAPI } from './handler';
17
- import { MessagePart } from './MessagePart';
18
- async function getModels() {
19
- return await requestAPI('configure');
20
- }
21
- /**
22
- * Main Chat component using Primer React
23
- */
24
- export const ChatComponent = () => {
25
- const [model, setModel] = useState('');
26
- const [enabledTools, setEnabledTools] = useState([]);
27
- const [inputValue, setInputValue] = useState('');
28
- const [showScrollButton, setShowScrollButton] = useState(false);
29
- const { messages, sendMessage, status, regenerate } = useAIJupyterChat();
30
- const textareaRef = useRef(null);
31
- const messagesEndRef = useRef(null);
32
- const scrollContainerRef = useRef(null);
33
- const configQuery = useQuery({
34
- queryFn: getModels,
35
- queryKey: ['models'],
36
- });
37
- useEffect(() => {
38
- if (configQuery.data) {
39
- setModel(configQuery.data.models[0].id);
40
- // Enable all builtin tools by default
41
- const allToolIds = configQuery.data.builtinTools?.map(tool => tool.id) || [];
42
- setEnabledTools(allToolIds);
43
- }
44
- }, [configQuery.data]);
45
- // Auto-scroll to bottom when new messages arrive
46
- useEffect(() => {
47
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
48
- }, [messages]);
49
- // Handle scroll to show/hide scroll button
50
- useEffect(() => {
51
- const container = scrollContainerRef.current;
52
- if (!container)
53
- return;
54
- const handleScroll = () => {
55
- const isScrolledUp = container.scrollHeight - container.scrollTop - container.clientHeight >
56
- 100;
57
- setShowScrollButton(isScrolledUp);
58
- };
59
- container.addEventListener('scroll', handleScroll);
60
- return () => container.removeEventListener('scroll', handleScroll);
61
- }, []);
62
- const handleSubmit = (e) => {
63
- e.preventDefault();
64
- if (inputValue.trim() && status !== 'streaming') {
65
- sendMessage({ text: inputValue }, {
66
- body: { model, builtinTools: enabledTools },
67
- }).catch((error) => {
68
- console.error('Error sending message:', error);
69
- });
70
- setInputValue('');
71
- textareaRef.current?.focus();
72
- }
73
- };
74
- const handleKeyDown = (e) => {
75
- if (e.key === 'Enter' && !e.shiftKey) {
76
- e.preventDefault();
77
- handleSubmit(e);
78
- }
79
- };
80
- const regen = (id) => {
81
- regenerate({ messageId: id }).catch((error) => {
82
- console.error('Error regenerating message:', error);
83
- });
84
- };
85
- const scrollToBottom = () => {
86
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
87
- };
88
- const availableTools = useMemo(() => {
89
- if (!configQuery.data)
90
- return [];
91
- const selectedModel = configQuery.data.models.find(entry => entry.id === model);
92
- const enabledToolIds = selectedModel?.builtinTools ?? [];
93
- // If model doesn't specify tools, show all builtin tools
94
- const tools = enabledToolIds.length > 0
95
- ? (configQuery.data.builtinTools?.filter(tool => enabledToolIds.includes(tool.id)) ?? [])
96
- : (configQuery.data.builtinTools ?? []);
97
- return tools;
98
- }, [configQuery.data, model]);
99
- return (_jsxs(Box, { className: "dla-chat-root", sx: {
100
- position: 'absolute',
101
- top: 0,
102
- left: 0,
103
- right: 0,
104
- bottom: 0,
105
- display: 'flex',
106
- flexDirection: 'column',
107
- }, children: [_jsxs(Box, { ref: scrollContainerRef, className: "dla-chat-messages", sx: {
108
- position: 'absolute',
109
- top: 0,
110
- left: 0,
111
- right: 0,
112
- bottom: 0,
113
- overflowY: 'scroll',
114
- overflowX: 'hidden',
115
- padding: 3,
116
- paddingBottom: '180px',
117
- }, children: [messages.map(message => (_jsx(Box, { sx: { marginBottom: 3 }, children: message.parts.map((part, index) => (_jsx(MessagePart, { part: part, message: message, status: status, index: index, regen: regen, lastMessage: message.id === messages.at(-1)?.id }, `${message.id}-${index}`))) }, message.id))), status === 'submitted' && (_jsx(Box, { sx: { display: 'flex', justifyContent: 'center', padding: 3 }, children: _jsx(Spinner, { size: "medium" }) })), _jsx("div", { ref: messagesEndRef })] }), showScrollButton && (_jsx(Box, { sx: {
118
- position: 'absolute',
119
- bottom: 160,
120
- right: 16,
121
- zIndex: 1,
122
- }, children: _jsx(IconButton, { icon: ArrowDownIcon, "aria-label": "Scroll to bottom", onClick: scrollToBottom, variant: "default", size: "medium" }) })), _jsx(Box, { sx: {
123
- position: 'absolute',
124
- bottom: 0,
125
- left: 0,
126
- right: 0,
127
- borderTop: '1px solid',
128
- borderColor: 'border.default',
129
- padding: 3,
130
- backgroundColor: 'canvas.default',
131
- zIndex: 0,
132
- }, children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(FormControl, { sx: { width: '100%' }, children: _jsx(Textarea, { ref: textareaRef, value: inputValue, onChange: e => setInputValue(e.target.value), onKeyDown: handleKeyDown, placeholder: "Ask me anything...", rows: 3, resize: "vertical", sx: { marginBottom: 2, width: '100%' } }) }), _jsxs(Box, { sx: {
133
- display: 'flex',
134
- justifyContent: 'space-between',
135
- alignItems: 'center',
136
- }, children: [_jsxs(Box, { sx: { display: 'flex', gap: 2, alignItems: 'center' }, children: [availableTools.length > 0 && (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(IconButton, { icon: ToolsIcon, "aria-label": "Tools", variant: "invisible", size: "small" }) }), _jsx(ActionMenu.Overlay, { children: _jsx(ActionList, { children: _jsx(ActionList.Group, { title: "Available Tools", children: availableTools.map(tool => (_jsxs(ActionList.Item, { disabled: true, children: [_jsx(ActionList.LeadingVisual, { children: _jsx(Box, { sx: {
137
- width: 8,
138
- height: 8,
139
- borderRadius: '50%',
140
- backgroundColor: 'success.emphasis',
141
- } }) }), tool.name] }, tool.id))) }) }) })] })), configQuery.data && model && (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Button, { type: "button", variant: "invisible", size: "small", leadingVisual: AiModelIcon, children: _jsx(Text, { sx: { fontSize: 0 }, children: configQuery.data.models.find(m => m.id === model)
142
- ?.name || 'Select Model' }) }) }), _jsx(ActionMenu.Overlay, { children: _jsx(ActionList, { selectionVariant: "single", children: configQuery.data.models.map(modelItem => (_jsx(ActionList.Item, { selected: model === modelItem.id, onSelect: () => setModel(modelItem.id), children: modelItem.name }, modelItem.id))) }) })] }))] }), _jsx(Button, { type: "submit", variant: "primary", size: "small", disabled: !inputValue.trim() || status === 'streaming', leadingVisual: ArrowUpIcon, children: status === 'streaming' ? 'Sending...' : 'Send' })] })] }) })] }));
143
- };
@@ -1,11 +0,0 @@
1
- import type { UIDataTypes, UIMessagePart, UITools, UIMessage } from 'ai';
2
- interface IMessagePartProps {
3
- part: UIMessagePart<UIDataTypes, UITools>;
4
- message: UIMessage;
5
- status: string;
6
- regen: (id: string) => void;
7
- index: number;
8
- lastMessage: boolean;
9
- }
10
- export declare function MessagePart({ part, message, status, regen, index, lastMessage, }: IMessagePartProps): import("react/jsx-runtime").JSX.Element | null;
11
- export {};
@@ -1,23 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { TextPart } from './display/TextPart';
3
- import { ReasoningPart } from './display/ReasoningPart';
4
- import { ToolPart } from './display/ToolPart';
5
- import { DynamicToolPart } from './display/DynamicToolPart';
6
- export function MessagePart({ part, message, status, regen, index, lastMessage, }) {
7
- if (part.type === 'text') {
8
- return (_jsx(TextPart, { text: part.text, message: message, isLastPart: index === message.parts.length - 1, onRegenerate: regen }));
9
- }
10
- else if (part.type === 'reasoning') {
11
- const isStreaming = status === 'streaming' &&
12
- index === message.parts.length - 1 &&
13
- lastMessage;
14
- return _jsx(ReasoningPart, { text: part.text, isStreaming: isStreaming });
15
- }
16
- else if (part.type === 'dynamic-tool') {
17
- return _jsx(DynamicToolPart, { part: part });
18
- }
19
- else if ('toolCallId' in part) {
20
- return _jsx(ToolPart, { part: part });
21
- }
22
- return null;
23
- }
@@ -1,6 +0,0 @@
1
- import type { DynamicToolUIPart } from 'ai';
2
- interface IDynamicToolPartProps {
3
- part: DynamicToolUIPart;
4
- }
5
- export declare function DynamicToolPart({ part }: IDynamicToolPartProps): import("react/jsx-runtime").JSX.Element;
6
- export {};
@@ -1,5 +0,0 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { Text, Flash } from '@primer/react';
3
- export function DynamicToolPart({ part }) {
4
- return (_jsx(Flash, { variant: "warning", sx: { marginBottom: 2 }, children: _jsxs(Text, { children: ["Dynamic Tool: ", JSON.stringify(part)] }) }));
5
- }
@@ -1,6 +0,0 @@
1
- interface IReasoningPartProps {
2
- text: string;
3
- isStreaming: boolean;
4
- }
5
- export declare function ReasoningPart({ text, isStreaming }: IReasoningPartProps): import("react/jsx-runtime").JSX.Element;
6
- export {};