@eeacms/volto-eea-chatbot 2.0.5 → 3.0.1
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/.github/workflows/betterleaks.yml +133 -0
- package/.gitleaks.toml +89 -0
- package/AGENTS.md +230 -0
- package/CHANGELOG.md +40 -0
- package/README.md +59 -0
- package/RELEASE.md +1 -1
- package/locales/de/LC_MESSAGES/volto.po +44 -0
- package/locales/en/LC_MESSAGES/volto.po +44 -0
- package/locales/it/LC_MESSAGES/volto.po +44 -0
- package/locales/ro/LC_MESSAGES/volto.po +44 -0
- package/locales/volto.pot +46 -2
- package/package.json +2 -1
- package/src/AISearchInput/AISearchInputEdit.jsx +37 -0
- package/src/AISearchInput/AISearchInputView.jsx +130 -0
- package/src/AISearchInput/components/DeepResearchToggle.jsx +35 -0
- package/src/AISearchInput/components/DisclaimerText.jsx +10 -0
- package/src/AISearchInput/components/IntroHeader.jsx +24 -0
- package/src/AISearchInput/components/PromptChips.jsx +22 -0
- package/src/AISearchInput/components/SearchInput.jsx +53 -0
- package/src/AISearchInput/index.js +32 -0
- package/src/AISearchInput/messages.js +38 -0
- package/src/AISearchInput/schema.jsx +215 -0
- package/src/AISearchInput/styles.less +320 -0
- package/src/ChatBlock/ChatBlockView.jsx +4 -0
- package/src/ChatBlock/chat/ChatWindow.tsx +23 -0
- package/src/ChatBlock/packets/MultiToolRenderer.tsx +20 -11
- package/src/ChatBlock/services/messageProcessor.ts +32 -14
- package/src/ChatBlock/style.less +41 -51
- package/src/halloumi/filtering.js +2 -2
- package/src/halloumi/generative.test.js +1 -1
- package/src/halloumi/middleware.js +2 -2
- package/src/halloumi/middleware.test.js +5 -5
- package/src/icons/sparkle.svg +3 -0
- package/src/index.js +2 -0
- package/src/middleware.js +2 -2
- package/src/middleware.test.js +11 -11
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import messages from './messages';
|
|
2
|
+
|
|
3
|
+
export function AISearchInputSchema({ intl, data }) {
|
|
4
|
+
return {
|
|
5
|
+
title: intl.formatMessage(messages.aiSearchInput),
|
|
6
|
+
fieldsets: [
|
|
7
|
+
{
|
|
8
|
+
id: 'default',
|
|
9
|
+
title: intl.formatMessage({
|
|
10
|
+
id: 'Default',
|
|
11
|
+
defaultMessage: 'Default',
|
|
12
|
+
}),
|
|
13
|
+
fields: [
|
|
14
|
+
'assistantEndpoint',
|
|
15
|
+
'blockTitle',
|
|
16
|
+
'introText',
|
|
17
|
+
'showIcon',
|
|
18
|
+
'placeholderText',
|
|
19
|
+
'examplePromptsEnabled',
|
|
20
|
+
...(data.examplePromptsEnabled ? ['examplePrompts'] : []),
|
|
21
|
+
'deepResearch',
|
|
22
|
+
'disclaimerText',
|
|
23
|
+
'stylingVariant',
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
properties: {
|
|
28
|
+
assistantEndpoint: {
|
|
29
|
+
title: intl.formatMessage({
|
|
30
|
+
id: 'Assistant page URL',
|
|
31
|
+
defaultMessage: 'Assistant page URL',
|
|
32
|
+
}),
|
|
33
|
+
description: intl.formatMessage({
|
|
34
|
+
id: 'URL of the Plone page that contains the AI Chatbot block (e.g. /ai-assistant).',
|
|
35
|
+
defaultMessage:
|
|
36
|
+
'URL of the Plone page that contains the AI Chatbot block (e.g. /ai-assistant).',
|
|
37
|
+
}),
|
|
38
|
+
widget: 'url',
|
|
39
|
+
type: 'string',
|
|
40
|
+
},
|
|
41
|
+
blockTitle: {
|
|
42
|
+
title: intl.formatMessage({
|
|
43
|
+
id: 'Block title',
|
|
44
|
+
defaultMessage: 'Block title',
|
|
45
|
+
}),
|
|
46
|
+
description: intl.formatMessage({
|
|
47
|
+
id: 'Optional title displayed inline with the icon.',
|
|
48
|
+
defaultMessage: 'Optional title displayed inline with the icon.',
|
|
49
|
+
}),
|
|
50
|
+
type: 'string',
|
|
51
|
+
},
|
|
52
|
+
introText: {
|
|
53
|
+
title: intl.formatMessage({
|
|
54
|
+
id: 'Introductory text',
|
|
55
|
+
defaultMessage: 'Introductory text',
|
|
56
|
+
}),
|
|
57
|
+
description: intl.formatMessage({
|
|
58
|
+
id: 'Help text shown next to the icon and title.',
|
|
59
|
+
defaultMessage: 'Help text shown next to the icon and title.',
|
|
60
|
+
}),
|
|
61
|
+
widget: 'slate',
|
|
62
|
+
},
|
|
63
|
+
showIcon: {
|
|
64
|
+
title: intl.formatMessage({
|
|
65
|
+
id: 'Show icon',
|
|
66
|
+
defaultMessage: 'Show icon',
|
|
67
|
+
}),
|
|
68
|
+
type: 'boolean',
|
|
69
|
+
default: true,
|
|
70
|
+
},
|
|
71
|
+
placeholderText: {
|
|
72
|
+
title: intl.formatMessage({
|
|
73
|
+
id: 'Placeholder text',
|
|
74
|
+
defaultMessage: 'Placeholder text',
|
|
75
|
+
}),
|
|
76
|
+
type: 'string',
|
|
77
|
+
default: intl.formatMessage(messages.askYourQuestion),
|
|
78
|
+
},
|
|
79
|
+
examplePromptsEnabled: {
|
|
80
|
+
title: intl.formatMessage({
|
|
81
|
+
id: 'Show example prompts',
|
|
82
|
+
defaultMessage: 'Show example prompts',
|
|
83
|
+
}),
|
|
84
|
+
type: 'boolean',
|
|
85
|
+
default: false,
|
|
86
|
+
description: intl.formatMessage({
|
|
87
|
+
id: 'When enabled, editors can define clickable prompt chips below the input.',
|
|
88
|
+
defaultMessage:
|
|
89
|
+
'When enabled, editors can define clickable prompt chips below the input.',
|
|
90
|
+
}),
|
|
91
|
+
},
|
|
92
|
+
examplePrompts: {
|
|
93
|
+
title: intl.formatMessage({
|
|
94
|
+
id: 'Example prompts',
|
|
95
|
+
defaultMessage: 'Example prompts',
|
|
96
|
+
}),
|
|
97
|
+
widget: 'object_list',
|
|
98
|
+
schema: {
|
|
99
|
+
title: intl.formatMessage({
|
|
100
|
+
id: 'Prompt',
|
|
101
|
+
defaultMessage: 'Prompt',
|
|
102
|
+
}),
|
|
103
|
+
fieldsets: [
|
|
104
|
+
{
|
|
105
|
+
id: 'default',
|
|
106
|
+
title: intl.formatMessage({
|
|
107
|
+
id: 'Default',
|
|
108
|
+
defaultMessage: 'Default',
|
|
109
|
+
}),
|
|
110
|
+
fields: ['label', 'message'],
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
properties: {
|
|
114
|
+
label: {
|
|
115
|
+
title: intl.formatMessage({
|
|
116
|
+
id: 'Label',
|
|
117
|
+
defaultMessage: 'Label',
|
|
118
|
+
}),
|
|
119
|
+
description: intl.formatMessage({
|
|
120
|
+
id: 'Text displayed on the chip button.',
|
|
121
|
+
defaultMessage: 'Text displayed on the chip button.',
|
|
122
|
+
}),
|
|
123
|
+
},
|
|
124
|
+
message: {
|
|
125
|
+
title: intl.formatMessage({
|
|
126
|
+
id: 'Message',
|
|
127
|
+
defaultMessage: 'Message',
|
|
128
|
+
}),
|
|
129
|
+
type: 'string',
|
|
130
|
+
description: intl.formatMessage({
|
|
131
|
+
id: 'Optional — the actual query sent when clicked. If empty, uses the label.',
|
|
132
|
+
defaultMessage:
|
|
133
|
+
'Optional — the actual query sent when clicked. If empty, uses the label.',
|
|
134
|
+
}),
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
required: ['label'],
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
deepResearch: {
|
|
141
|
+
title: intl.formatMessage(messages.deepResearch),
|
|
142
|
+
choices: [
|
|
143
|
+
[
|
|
144
|
+
'unavailable',
|
|
145
|
+
intl.formatMessage({
|
|
146
|
+
id: 'Unavailable',
|
|
147
|
+
defaultMessage: 'Unavailable',
|
|
148
|
+
}),
|
|
149
|
+
],
|
|
150
|
+
[
|
|
151
|
+
'always_on',
|
|
152
|
+
intl.formatMessage({
|
|
153
|
+
id: 'Always on',
|
|
154
|
+
defaultMessage: 'Always on',
|
|
155
|
+
}),
|
|
156
|
+
],
|
|
157
|
+
[
|
|
158
|
+
'user_on',
|
|
159
|
+
intl.formatMessage({
|
|
160
|
+
id: 'User choice, on by default',
|
|
161
|
+
defaultMessage: 'User choice, on by default',
|
|
162
|
+
}),
|
|
163
|
+
],
|
|
164
|
+
[
|
|
165
|
+
'user_off',
|
|
166
|
+
intl.formatMessage({
|
|
167
|
+
id: 'User choice, off by default',
|
|
168
|
+
defaultMessage: 'User choice, off by default',
|
|
169
|
+
}),
|
|
170
|
+
],
|
|
171
|
+
],
|
|
172
|
+
default: 'unavailable',
|
|
173
|
+
},
|
|
174
|
+
disclaimerText: {
|
|
175
|
+
title: intl.formatMessage({
|
|
176
|
+
id: 'Disclaimer text',
|
|
177
|
+
defaultMessage: 'Disclaimer text',
|
|
178
|
+
}),
|
|
179
|
+
widget: 'slate',
|
|
180
|
+
description: intl.formatMessage({
|
|
181
|
+
id: 'AI transparency text. Always displayed at the bottom of the block.',
|
|
182
|
+
defaultMessage:
|
|
183
|
+
'AI transparency text. Always displayed at the bottom of the block.',
|
|
184
|
+
}),
|
|
185
|
+
default: [
|
|
186
|
+
{
|
|
187
|
+
type: 'p',
|
|
188
|
+
children: [
|
|
189
|
+
{ text: intl.formatMessage(messages.defaultDisclaimer) },
|
|
190
|
+
],
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
},
|
|
194
|
+
stylingVariant: {
|
|
195
|
+
title: intl.formatMessage({
|
|
196
|
+
id: 'Styling variant',
|
|
197
|
+
defaultMessage: 'Styling variant',
|
|
198
|
+
}),
|
|
199
|
+
choices: [
|
|
200
|
+
['dark', intl.formatMessage({ id: 'Dark', defaultMessage: 'Dark' })],
|
|
201
|
+
[
|
|
202
|
+
'light',
|
|
203
|
+
intl.formatMessage({ id: 'Light', defaultMessage: 'Light' }),
|
|
204
|
+
],
|
|
205
|
+
[
|
|
206
|
+
'accent',
|
|
207
|
+
intl.formatMessage({ id: 'Accent', defaultMessage: 'Accent' }),
|
|
208
|
+
],
|
|
209
|
+
],
|
|
210
|
+
default: 'dark',
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
required: ['assistantEndpoint'],
|
|
214
|
+
};
|
|
215
|
+
}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
// AI Search Input styles — scoped under .ais-search-input
|
|
2
|
+
// Uses EEA Design System tokens
|
|
3
|
+
|
|
4
|
+
@import '@eeacms/volto-design-tokens/src/colors';
|
|
5
|
+
@import '@eeacms/volto-design-tokens/src/shapes';
|
|
6
|
+
@import '@eeacms/volto-design-tokens/src/borders';
|
|
7
|
+
@import '@eeacms/volto-design-tokens/src/fonts';
|
|
8
|
+
|
|
9
|
+
// Spacing tokens from @eeacms/volto-design-tokens/src/sizes
|
|
10
|
+
// (imported manually to avoid @1px Semantic UI dependency)
|
|
11
|
+
@spacer: 4px;
|
|
12
|
+
@space-025: @spacer * 0.25;
|
|
13
|
+
@space-05: @spacer * 0.5;
|
|
14
|
+
@space-1: @spacer * 1;
|
|
15
|
+
@space-2: @spacer * 2;
|
|
16
|
+
@space-3: @spacer * 3;
|
|
17
|
+
@space-4: @spacer * 4;
|
|
18
|
+
@space-5: @spacer * 5;
|
|
19
|
+
@space-6: @spacer * 6;
|
|
20
|
+
@space-8: @spacer * 8;
|
|
21
|
+
|
|
22
|
+
// Size tokens
|
|
23
|
+
@size-10: 120px;
|
|
24
|
+
|
|
25
|
+
.ais-search-input {
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
padding: @space-6;
|
|
29
|
+
gap: @space-3;
|
|
30
|
+
|
|
31
|
+
// --- Dark variant (default) ---
|
|
32
|
+
&.ais-dark {
|
|
33
|
+
background-color: @blue-6;
|
|
34
|
+
color: @grey-0;
|
|
35
|
+
|
|
36
|
+
.ais-chip {
|
|
37
|
+
background-color: @blue-5;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.ais-search-input-field {
|
|
41
|
+
border-bottom-color: @grey-0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.ais-input-error {
|
|
45
|
+
color: @red-2;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// --- Light variant ---
|
|
50
|
+
&.ais-light {
|
|
51
|
+
background-color: @grey-1;
|
|
52
|
+
color: @grey-5;
|
|
53
|
+
|
|
54
|
+
.ais-chip {
|
|
55
|
+
background-color: @grey-2;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.ais-search-input-field {
|
|
59
|
+
border-bottom-color: @grey-5;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.ais-input-error {
|
|
63
|
+
color: @red-5;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// --- Accent variant (EEA green/teal) ---
|
|
68
|
+
&.ais-accent {
|
|
69
|
+
background-color: @green-5;
|
|
70
|
+
color: @grey-0;
|
|
71
|
+
|
|
72
|
+
.ais-chip {
|
|
73
|
+
background-color: @green-4;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.ais-search-input-field {
|
|
77
|
+
border-bottom-color: @grey-0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.ais-input-error {
|
|
81
|
+
color: @red-1;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// --- Intro header (Row 1) ---
|
|
86
|
+
.ais-intro-header {
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: flex-start;
|
|
89
|
+
gap: @space-2;
|
|
90
|
+
|
|
91
|
+
.ais-icon {
|
|
92
|
+
flex-shrink: 0;
|
|
93
|
+
margin-top: @space-05;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.ais-intro-content {
|
|
97
|
+
display: flex;
|
|
98
|
+
flex-direction: column;
|
|
99
|
+
gap: @space-05;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.ais-block-title {
|
|
103
|
+
font-size: @font-size-1;
|
|
104
|
+
font-weight: @font-weight-6;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Slate-rendered intro text
|
|
108
|
+
:global(.slate-editor) {
|
|
109
|
+
margin: 0;
|
|
110
|
+
font-size: @font-size-0;
|
|
111
|
+
line-height: @font-lineheight-2;
|
|
112
|
+
|
|
113
|
+
p {
|
|
114
|
+
margin: 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
a {
|
|
118
|
+
color: inherit;
|
|
119
|
+
text-decoration: underline;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// --- Search input (Row 2) ---
|
|
125
|
+
.ais-search-input-field {
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
padding-bottom: @space-1;
|
|
129
|
+
border-bottom: @border-size-2 solid currentColor;
|
|
130
|
+
|
|
131
|
+
input {
|
|
132
|
+
flex: 1;
|
|
133
|
+
padding: @space-1 0;
|
|
134
|
+
border: none;
|
|
135
|
+
background: transparent;
|
|
136
|
+
color: inherit;
|
|
137
|
+
font-family: inherit;
|
|
138
|
+
font-size: @font-size-1;
|
|
139
|
+
outline: none;
|
|
140
|
+
|
|
141
|
+
&::placeholder {
|
|
142
|
+
color: inherit;
|
|
143
|
+
opacity: 0.6;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.ais-submit-btn {
|
|
148
|
+
display: flex;
|
|
149
|
+
flex-shrink: 0;
|
|
150
|
+
align-items: center;
|
|
151
|
+
padding: @space-1;
|
|
152
|
+
border: none;
|
|
153
|
+
background: none;
|
|
154
|
+
color: inherit;
|
|
155
|
+
cursor: pointer;
|
|
156
|
+
transition: opacity 0.2s;
|
|
157
|
+
|
|
158
|
+
&:hover {
|
|
159
|
+
opacity: 0.8;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
&:focus-visible {
|
|
163
|
+
border-radius: @radius-1;
|
|
164
|
+
outline: @border-size-2 solid currentColor;
|
|
165
|
+
outline-offset: @space-05;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.ais-input-error {
|
|
171
|
+
width: 100%;
|
|
172
|
+
margin-top: @space-1;
|
|
173
|
+
font-size: @font-size-00;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// --- Controls row: chips (left) + deep research toggle (right) ---
|
|
177
|
+
.ais-controls-row {
|
|
178
|
+
display: flex;
|
|
179
|
+
flex-wrap: wrap;
|
|
180
|
+
align-items: center;
|
|
181
|
+
gap: @space-2;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// --- Prompt chips ---
|
|
185
|
+
.ais-prompt-chips {
|
|
186
|
+
display: flex;
|
|
187
|
+
flex: 1;
|
|
188
|
+
flex-wrap: wrap;
|
|
189
|
+
gap: @space-2;
|
|
190
|
+
|
|
191
|
+
.ais-chip {
|
|
192
|
+
padding: @space-1 @space-3;
|
|
193
|
+
border: none;
|
|
194
|
+
border-radius: @radius-0;
|
|
195
|
+
color: inherit;
|
|
196
|
+
cursor: pointer;
|
|
197
|
+
font-family: inherit;
|
|
198
|
+
font-size: @font-size-0;
|
|
199
|
+
transition: opacity 0.2s;
|
|
200
|
+
|
|
201
|
+
&:hover {
|
|
202
|
+
opacity: 0.85;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
&:focus-visible {
|
|
206
|
+
outline: @border-size-2 solid currentColor;
|
|
207
|
+
outline-offset: @space-05;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// --- Deep research toggle (right-aligned) ---
|
|
213
|
+
.ais-deep-research {
|
|
214
|
+
display: flex;
|
|
215
|
+
flex-shrink: 0;
|
|
216
|
+
align-items: center;
|
|
217
|
+
margin-left: auto;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.ais-deep-research-label {
|
|
221
|
+
font-size: @font-size-00;
|
|
222
|
+
opacity: 0.8;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Custom toggle switch
|
|
226
|
+
.ais-toggle {
|
|
227
|
+
display: inline-flex;
|
|
228
|
+
align-items: center;
|
|
229
|
+
cursor: pointer;
|
|
230
|
+
font-size: @font-size-0;
|
|
231
|
+
gap: @space-2;
|
|
232
|
+
|
|
233
|
+
input {
|
|
234
|
+
display: none;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.ais-toggle-slider {
|
|
238
|
+
position: relative;
|
|
239
|
+
display: inline-block;
|
|
240
|
+
width: 28px;
|
|
241
|
+
height: 16px;
|
|
242
|
+
border: @border-size-1 solid currentColor;
|
|
243
|
+
border-radius: @radius-3;
|
|
244
|
+
background-color: rgba(currentColor, 0.15);
|
|
245
|
+
transition: background-color 0.2s;
|
|
246
|
+
|
|
247
|
+
&::before {
|
|
248
|
+
position: absolute;
|
|
249
|
+
top: 1px;
|
|
250
|
+
left: 2px;
|
|
251
|
+
display: block;
|
|
252
|
+
width: 12px;
|
|
253
|
+
height: 12px;
|
|
254
|
+
border-radius: 50%;
|
|
255
|
+
background-color: currentColor;
|
|
256
|
+
content: '';
|
|
257
|
+
transition: left 0.2s;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
input:checked ~ .ais-toggle-slider {
|
|
262
|
+
border-color: @green-4;
|
|
263
|
+
background-color: @green-4;
|
|
264
|
+
|
|
265
|
+
&::before {
|
|
266
|
+
left: 13px;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// --- Disclaimer (Row 5) ---
|
|
272
|
+
.ais-disclaimer {
|
|
273
|
+
margin-top: @space-1;
|
|
274
|
+
font-size: @font-size-00;
|
|
275
|
+
opacity: 0.7;
|
|
276
|
+
|
|
277
|
+
:global(.slate-editor) {
|
|
278
|
+
font-size: inherit;
|
|
279
|
+
|
|
280
|
+
p {
|
|
281
|
+
margin: 0;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
a {
|
|
285
|
+
color: inherit;
|
|
286
|
+
text-decoration: underline;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// --- Responsive ---
|
|
292
|
+
@media (max-width: 768px) {
|
|
293
|
+
padding: @space-4;
|
|
294
|
+
gap: @space-2;
|
|
295
|
+
|
|
296
|
+
.ais-intro-header {
|
|
297
|
+
.ais-icon {
|
|
298
|
+
width: @space-5;
|
|
299
|
+
height: @space-5;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.ais-block-title {
|
|
303
|
+
font-size: @font-size-0;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
:global(.slate-editor) {
|
|
307
|
+
font-size: @font-size-00;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.ais-search-input-field input {
|
|
312
|
+
font-size: @font-size-0;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.ais-prompt-chips .ais-chip {
|
|
316
|
+
min-width: @size-10;
|
|
317
|
+
flex: 1 1 auto;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
@@ -13,6 +13,8 @@ function ChatBlockView(props) {
|
|
|
13
13
|
);
|
|
14
14
|
|
|
15
15
|
const isPlaywrightTest = query.playwright === 'yes';
|
|
16
|
+
const initialQuery = query.query || null;
|
|
17
|
+
const initialDeepResearch = query.deepResearch || null;
|
|
16
18
|
|
|
17
19
|
useEffect(() => {
|
|
18
20
|
if (isPlaywrightTest) {
|
|
@@ -29,6 +31,8 @@ function ChatBlockView(props) {
|
|
|
29
31
|
isEditMode={isEditMode}
|
|
30
32
|
isPlaywrightTest={isPlaywrightTest}
|
|
31
33
|
block_id={id}
|
|
34
|
+
initialQuery={initialQuery}
|
|
35
|
+
initialDeepResearch={initialDeepResearch}
|
|
32
36
|
{...data}
|
|
33
37
|
/>
|
|
34
38
|
) : (
|
|
@@ -5,6 +5,7 @@ import React, {
|
|
|
5
5
|
useMemo,
|
|
6
6
|
useCallback,
|
|
7
7
|
} from 'react';
|
|
8
|
+
import { useHistory } from 'react-router-dom';
|
|
8
9
|
import type { Persona } from '@eeacms/volto-eea-chatbot/ChatBlock/types/interfaces';
|
|
9
10
|
import { Button, Form, Segment, Checkbox } from 'semantic-ui-react';
|
|
10
11
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable';
|
|
@@ -50,6 +51,8 @@ interface ChatWindowProps {
|
|
|
50
51
|
maxContextSegments?: number;
|
|
51
52
|
onyxVersion?: '2' | '3';
|
|
52
53
|
isPlaywrightTest?: boolean;
|
|
54
|
+
initialQuery?: string | null;
|
|
55
|
+
initialDeepResearch?: string | null;
|
|
53
56
|
[key: string]: any;
|
|
54
57
|
}
|
|
55
58
|
|
|
@@ -61,6 +64,8 @@ function ChatWindow({
|
|
|
61
64
|
placeholderPrompt = 'Ask a question',
|
|
62
65
|
isEditMode,
|
|
63
66
|
isPlaywrightTest,
|
|
67
|
+
initialQuery,
|
|
68
|
+
initialDeepResearch,
|
|
64
69
|
...data
|
|
65
70
|
}: ChatWindowProps) {
|
|
66
71
|
const {
|
|
@@ -124,6 +129,7 @@ function ChatWindow({
|
|
|
124
129
|
|
|
125
130
|
const [showLandingPage, setShowLandingPage] = useState(true);
|
|
126
131
|
|
|
132
|
+
const history = useHistory();
|
|
127
133
|
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
|
128
134
|
const chatWindowRef = useRef(null);
|
|
129
135
|
const chatWindowEndRef = useRef(null);
|
|
@@ -132,6 +138,23 @@ function ChatWindow({
|
|
|
132
138
|
setShowLandingPage(messages.length === 0);
|
|
133
139
|
}, [messages]);
|
|
134
140
|
|
|
141
|
+
// Set deep research state from URL parameter
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
if (initialDeepResearch !== null && initialDeepResearch !== undefined) {
|
|
144
|
+
const enabled = initialDeepResearch.toLowerCase() === 'true';
|
|
145
|
+
setIsDeepResearchEnabled(enabled);
|
|
146
|
+
}
|
|
147
|
+
}, []);
|
|
148
|
+
|
|
149
|
+
// Auto-submit query from URL parameter on mount
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
if (initialQuery && messages.length === 0 && !isStreaming) {
|
|
152
|
+
onSubmit({ message: initialQuery });
|
|
153
|
+
setShowLandingPage(false);
|
|
154
|
+
history.replace(window.location.pathname);
|
|
155
|
+
}
|
|
156
|
+
}, []);
|
|
157
|
+
|
|
135
158
|
const handleStarterPromptChoice = useCallback(
|
|
136
159
|
(message: string) => {
|
|
137
160
|
if (enableMatomoTracking) {
|
|
@@ -133,7 +133,14 @@ export function MultiToolRenderer({
|
|
|
133
133
|
{filteredToolGroups.map((toolGroup, index) => {
|
|
134
134
|
const isLastItem = index === filteredToolGroups.length - 1;
|
|
135
135
|
const toolState = toolStates.get(toolGroup.ind);
|
|
136
|
-
const isToolCompleted = toolState?.isCompleted;
|
|
136
|
+
const isToolCompleted = toolState?.isCompleted === true;
|
|
137
|
+
const isToolActive =
|
|
138
|
+
isOverallStreaming && !isToolCompleted && isLastItem;
|
|
139
|
+
const toolDisplayState = isToolActive
|
|
140
|
+
? 'active'
|
|
141
|
+
: isToolCompleted
|
|
142
|
+
? 'completed'
|
|
143
|
+
: 'pending';
|
|
137
144
|
|
|
138
145
|
return (
|
|
139
146
|
<div
|
|
@@ -141,6 +148,8 @@ export function MultiToolRenderer({
|
|
|
141
148
|
className={cx({
|
|
142
149
|
'tool-collapsed-wrapper': isOverallStreaming,
|
|
143
150
|
})}
|
|
151
|
+
data-state={toolDisplayState}
|
|
152
|
+
aria-current={isToolActive ? 'step' : undefined}
|
|
144
153
|
>
|
|
145
154
|
<RendererComponent
|
|
146
155
|
packets={toolGroup.packets}
|
|
@@ -158,12 +167,7 @@ export function MultiToolRenderer({
|
|
|
158
167
|
const finalIcon = icon ? (
|
|
159
168
|
React.createElement(icon, { size: 14 })
|
|
160
169
|
) : (
|
|
161
|
-
<span
|
|
162
|
-
className={cx({
|
|
163
|
-
'tool-icon-dot': isOverallStreaming,
|
|
164
|
-
'tool-icon-default': !isOverallStreaming,
|
|
165
|
-
})}
|
|
166
|
-
/>
|
|
170
|
+
<span className="tool-icon-dot" />
|
|
167
171
|
);
|
|
168
172
|
|
|
169
173
|
// If tool is not completed and we are overall streaming, show collapsed view
|
|
@@ -184,14 +188,14 @@ export function MultiToolRenderer({
|
|
|
184
188
|
return (
|
|
185
189
|
<div
|
|
186
190
|
className={cx('tool-item-collapsed', {
|
|
187
|
-
active:
|
|
191
|
+
active: isToolActive,
|
|
188
192
|
completed: isToolCompleted,
|
|
189
193
|
})}
|
|
190
194
|
>
|
|
191
195
|
<div className="tool-collapsed-icon">
|
|
192
196
|
{finalIcon}
|
|
193
197
|
</div>
|
|
194
|
-
<span className="tool-collapsed-status">
|
|
198
|
+
<span className="tool-status tool-collapsed-status">
|
|
195
199
|
{status}
|
|
196
200
|
</span>
|
|
197
201
|
</div>
|
|
@@ -199,9 +203,14 @@ export function MultiToolRenderer({
|
|
|
199
203
|
}
|
|
200
204
|
}
|
|
201
205
|
|
|
202
|
-
//
|
|
206
|
+
// Detailed view for streaming reasoning/search tools and completed tools
|
|
203
207
|
return (
|
|
204
|
-
<div
|
|
208
|
+
<div
|
|
209
|
+
className={cx('tool-item-expanded', {
|
|
210
|
+
active: isToolActive,
|
|
211
|
+
completed: isToolCompleted,
|
|
212
|
+
})}
|
|
213
|
+
>
|
|
205
214
|
<div className="tool-connector-line" />
|
|
206
215
|
|
|
207
216
|
<div className="tool-item-row">
|