@eeacms/volto-eea-chatbot 2.0.1 → 2.0.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/.eslintrc.js +6 -6
- package/CHANGELOG.md +20 -0
- package/artifacts/ONYX_V3_INTEGRATION.md +34 -0
- package/jest-addon.config.js +2 -1
- package/package.json +1 -1
- package/src/ChatBlock/ChatBlockEdit.jsx +2 -1
- package/src/ChatBlock/chat/AIMessage.tsx +36 -16
- package/src/ChatBlock/chat/ChatMessage.tsx +1 -1
- package/src/ChatBlock/chat/ChatWindow.tsx +13 -11
- package/src/ChatBlock/chat/UserMessage.tsx +4 -4
- package/src/ChatBlock/components/AutoResizeTextarea.jsx +1 -1
- package/src/ChatBlock/components/ChatMessageFeedback.jsx +2 -2
- package/src/ChatBlock/components/EmptyState.jsx +1 -1
- package/src/ChatBlock/components/FeedbackModal.jsx +1 -1
- package/src/ChatBlock/components/HalloumiFeedback.jsx +2 -2
- package/src/ChatBlock/components/Source.jsx +2 -2
- package/src/ChatBlock/components/UserActionsToolbar.jsx +3 -3
- package/src/ChatBlock/components/WebResultIcon.tsx +2 -2
- package/src/ChatBlock/components/markdown/ClaimModal.jsx +3 -3
- package/src/ChatBlock/components/markdown/ClaimSegments.jsx +4 -4
- package/src/ChatBlock/components/markdown/{index.js → index.jsx} +1 -1
- package/src/ChatBlock/hooks/useChatController.ts +67 -14
- package/src/ChatBlock/hooks/useChatStreaming.ts +4 -4
- package/src/ChatBlock/hooks/useToolDisplayTiming.ts +2 -1
- package/src/ChatBlock/packets/MultiToolRenderer.tsx +86 -56
- package/src/ChatBlock/packets/RendererComponent.tsx +13 -5
- package/src/ChatBlock/packets/renderers/CustomToolRenderer.tsx +3 -3
- package/src/ChatBlock/packets/renderers/FetchToolRenderer.tsx +3 -3
- package/src/ChatBlock/packets/renderers/ImageToolRenderer.tsx +3 -3
- package/src/ChatBlock/packets/renderers/MessageTextRenderer.tsx +14 -9
- package/src/ChatBlock/packets/renderers/ReasoningRenderer.tsx +6 -5
- package/src/ChatBlock/packets/renderers/SearchToolRenderer.tsx +30 -21
- package/src/ChatBlock/{schema.js → schema.jsx} +13 -0
- package/src/ChatBlock/services/messageProcessor.ts +72 -17
- package/src/ChatBlock/services/packetUtils.ts +13 -3
- package/src/ChatBlock/services/streamingService.ts +155 -68
- package/src/ChatBlock/types/streamingModels.ts +47 -2
- package/src/ChatBlock/utils/citations.ts +1 -1
- package/src/halloumi/filtering.test.js +199 -1
- package/src/middleware.js +18 -1
- package/src/middleware.test.js +14 -0
- package/src/ChatBlock/tests/AIMessage.test.jsx +0 -95
- package/src/ChatBlock/tests/AutoResizeTextarea.test.jsx +0 -49
- package/src/ChatBlock/tests/BlinkingDot.test.jsx +0 -71
- package/src/ChatBlock/tests/ChatMessage.test.jsx +0 -75
- package/src/ChatBlock/tests/ChatMessageFeedback.test.jsx +0 -73
- package/src/ChatBlock/tests/Citation.test.jsx +0 -107
- package/src/ChatBlock/tests/ClaimModal.test.jsx +0 -136
- package/src/ChatBlock/tests/ClaimSegments.test.jsx +0 -206
- package/src/ChatBlock/tests/CustomToolRenderer.test.jsx +0 -241
- package/src/ChatBlock/tests/EmptyState.test.jsx +0 -137
- package/src/ChatBlock/tests/FeedbackModal.test.jsx +0 -138
- package/src/ChatBlock/tests/FetchToolRenderer.test.jsx +0 -161
- package/src/ChatBlock/tests/HalloumiFeedback.test.jsx +0 -94
- package/src/ChatBlock/tests/ImageToolRenderer.test.jsx +0 -178
- package/src/ChatBlock/tests/MessageTextRenderer.test.jsx +0 -227
- package/src/ChatBlock/tests/MultiToolRenderer.test.jsx +0 -134
- package/src/ChatBlock/tests/QualityCheckToggle.test.jsx +0 -105
- package/src/ChatBlock/tests/ReasoningRenderer.test.jsx +0 -163
- package/src/ChatBlock/tests/RelatedQuestions.test.jsx +0 -215
- package/src/ChatBlock/tests/RenderClaimView.test.jsx +0 -191
- package/src/ChatBlock/tests/RendererComponent.test.jsx +0 -139
- package/src/ChatBlock/tests/SearchToolRenderer.test.jsx +0 -295
- package/src/ChatBlock/tests/Source.test.jsx +0 -79
- package/src/ChatBlock/tests/SourceChip.test.jsx +0 -108
- package/src/ChatBlock/tests/Spinner.test.jsx +0 -18
- package/src/ChatBlock/tests/UserActionsToolbar.test.jsx +0 -135
- package/src/ChatBlock/tests/UserMessage.test.jsx +0 -83
- package/src/ChatBlock/tests/WebResultIcon.test.jsx +0 -61
- package/src/ChatBlock/tests/citations.test.js +0 -114
- package/src/ChatBlock/tests/index.test.js +0 -51
- package/src/ChatBlock/tests/messageProcessor.test.jsx +0 -438
- package/src/ChatBlock/tests/packetUtils.test.js +0 -158
- package/src/ChatBlock/tests/schema.test.js +0 -166
- package/src/ChatBlock/tests/streamingService.test.js +0 -467
- package/src/ChatBlock/tests/useChatController.test.jsx +0 -268
- package/src/ChatBlock/tests/useChatStreaming.test.jsx +0 -163
- package/src/ChatBlock/tests/useDeepCompareMemoize.test.js +0 -107
- package/src/ChatBlock/tests/useMarked.test.jsx +0 -107
- package/src/ChatBlock/tests/useQualityMarkers.test.jsx +0 -150
- package/src/ChatBlock/tests/useScrollonStream.test.jsx +0 -121
- package/src/ChatBlock/tests/useToolDisplayTiming.test.jsx +0 -151
- package/src/ChatBlock/tests/utils.test.jsx +0 -241
- package/src/ChatBlock/tests/withOnyxData.test.jsx +0 -81
package/.eslintrc.js
CHANGED
|
@@ -16,16 +16,16 @@ if (configFile) {
|
|
|
16
16
|
voltoPath = `./${jsConfig.baseUrl}/${pathsConfig['@plone/volto'][0]}`;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const
|
|
20
|
-
const
|
|
19
|
+
const { AddonRegistry } = require('@plone/registry/addon-registry');
|
|
20
|
+
const { registry } = AddonRegistry.init(projectRootPath);
|
|
21
21
|
|
|
22
22
|
// Extends ESlint configuration for adding aliases to `src` directories in Volto addons
|
|
23
|
-
const addonAliases = Object.keys(
|
|
23
|
+
const addonAliases = Object.keys(registry.packages).map((o) => [
|
|
24
24
|
o,
|
|
25
|
-
|
|
25
|
+
registry.packages[o].modulePath,
|
|
26
26
|
]);
|
|
27
27
|
|
|
28
|
-
const addonExtenders =
|
|
28
|
+
const addonExtenders = registry.getEslintExtenders().map((m) => require(m));
|
|
29
29
|
|
|
30
30
|
const defaultConfig = {
|
|
31
31
|
extends: `${voltoPath}/.eslintrc`,
|
|
@@ -34,7 +34,7 @@ const defaultConfig = {
|
|
|
34
34
|
alias: {
|
|
35
35
|
map: [
|
|
36
36
|
['@plone/volto', '@plone/volto/src'],
|
|
37
|
-
['@plone/volto-slate', '@plone/volto
|
|
37
|
+
['@plone/volto-slate', '@plone/volto-slate/src'],
|
|
38
38
|
...addonAliases,
|
|
39
39
|
['@package', `${__dirname}/src`],
|
|
40
40
|
['@root', `${__dirname}/src`],
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
### [2.0.3](https://github.com/eea/volto-eea-chatbot/compare/2.0.2...2.0.3) - 18 May 2026
|
|
8
|
+
|
|
9
|
+
#### :rocket: New Features
|
|
10
|
+
|
|
11
|
+
- feat: integrate Onyx 3.x support [Zoltan Szabo - [`6b0d9d5`](https://github.com/eea/volto-eea-chatbot/commit/6b0d9d5a847995953680a5a9a46281bfc3997b70)]
|
|
12
|
+
|
|
13
|
+
#### :house: Internal changes
|
|
14
|
+
|
|
15
|
+
- style: Automated code fix [eea-jenkins - [`ba195ce`](https://github.com/eea/volto-eea-chatbot/commit/ba195cec917b06faa70211b05c7def1d025d5356)]
|
|
16
|
+
|
|
17
|
+
#### :hammer_and_wrench: Others
|
|
18
|
+
|
|
19
|
+
- fixes for eslint [Zoltan Szabo - [`ec926dd`](https://github.com/eea/volto-eea-chatbot/commit/ec926dd32106105fb87cff226b5f92a495a1eadf)]
|
|
20
|
+
- increase test coverage [Zoltan Szabo - [`d4d1178`](https://github.com/eea/volto-eea-chatbot/commit/d4d1178fd52d215a755480c710b300f71f674f3f)]
|
|
21
|
+
- Rather than dealing with complex and fragile Webpack/Babel config transpilation rules for ES Modules, the cleanest solution is to remove the dependency entirely [Zoltan Szabo - [`3cdedee`](https://github.com/eea/volto-eea-chatbot/commit/3cdedee16ecddf695779b179eb6beeecde16295d)]
|
|
22
|
+
- updated snapshots [Zoltan Szabo - [`58dd3b8`](https://github.com/eea/volto-eea-chatbot/commit/58dd3b8e7d795032338b3580e33cd10c24576911)]
|
|
23
|
+
- fixed jest-addon.config.js [Zoltan Szabo - [`95c4c6f`](https://github.com/eea/volto-eea-chatbot/commit/95c4c6f494c71a9d5e9171b7d56bb1609dccc9f3)]
|
|
24
|
+
- updated dependencies [Zoltan Szabo - [`44e174e`](https://github.com/eea/volto-eea-chatbot/commit/44e174e4c3634d11241f78b46d86deefe0ed6191)]
|
|
25
|
+
### [2.0.2](https://github.com/eea/volto-eea-chatbot/compare/2.0.1...2.0.2) - 9 April 2026
|
|
26
|
+
|
|
7
27
|
### [2.0.1](https://github.com/eea/volto-eea-chatbot/compare/2.0.0...2.0.1) - 2 April 2026
|
|
8
28
|
|
|
9
29
|
#### :bug: Bug Fixes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Onyx v3 Integration for Volto EEA Chatbot
|
|
2
|
+
|
|
3
|
+
This document summarizes the major architectural changes and features implemented to support **Onyx 3.x** while maintaining full backward compatibility with **Onyx 2.x**.
|
|
4
|
+
|
|
5
|
+
## 1. Version Switching & Configuration
|
|
6
|
+
- **Onyx Version Toggle**: Added a configuration setting in the Chat Block schema to switch between Onyx 2 and 3.
|
|
7
|
+
- **Dynamic Routing**: The `streamingService` now branches logic based on the selected version, targeting the appropriate API endpoints:
|
|
8
|
+
- **v2**: `/send-message`
|
|
9
|
+
- **v3**: `/send-chat-message`
|
|
10
|
+
|
|
11
|
+
## 2. Packet-Based Architecture (v3)
|
|
12
|
+
Implemented support for the new Onyx 3.x packet schema, which utilizes turn indices (`ind`) for better synchronization:
|
|
13
|
+
- **New Packet Types**: Integrated support for `search_tool_start`, `search_tool_queries_delta`, `search_tool_documents_delta`, `citation_info`, and `reasoning_done`.
|
|
14
|
+
- **Packet Normalization**: Developed a normalization layer in `streamingService.ts` to map v3 packets into the chatbot's internal `Packet` structure.
|
|
15
|
+
- **Turn Index Mapping**: Updated `MessageProcessor` to use explicit `ind` values from the backend for reliable turn completion detection, replacing the synthetic index fallback used in v2.
|
|
16
|
+
|
|
17
|
+
## 3. Streaming & UI Visibility
|
|
18
|
+
- **Eager Rendering**: Updated `MultiToolRenderer` and `SearchToolRenderer` to display search queries and documents as they arrive via delta packets, rather than waiting for tool completion.
|
|
19
|
+
- **Improved Context**: Added distinct labels for "Web Queries" and "Internal Search Queries" in the Search Tool UI.
|
|
20
|
+
- **Reasoning Support**: Enhanced `ReasoningRenderer` to handle v3 reasoning packets and provide a smoother transition between "thinking" and "answering" phases.
|
|
21
|
+
|
|
22
|
+
## 4. Related Questions (RQ) Restoration
|
|
23
|
+
- **Middleware Routing**: Updated the RQ workflow to route through the specialized `/_rq/` middleware proxy for both session creation and message sending.
|
|
24
|
+
- **Dedicated Sessions**: Ensured that Related Questions use a fresh chat session correctly targeting the QGen assistant on the appropriate version backend.
|
|
25
|
+
- **Completion Resiliency**: Patched a race condition where missing `section_end` packets for the main message turn would block RQ interrogation. The system now automatically synthesizes turn completion when the stream ends.
|
|
26
|
+
|
|
27
|
+
## 5. Middleware & Proxying
|
|
28
|
+
- **Proxy Expansion**: Synchronized `middleware.js` to handle both standard (`/_da/`) and related questions (`/_rq/`) paths for all v3 endpoints.
|
|
29
|
+
- **Payload Alignment**: Updated the payload builders to support v3-specific fields like `alternate_assistant_id`, `file_descriptors`, and `internal_search_filters`.
|
|
30
|
+
|
|
31
|
+
## 6. Bug Fixes & Stability
|
|
32
|
+
- **Citation Fallback**: Added a fallback for citations in v3 if explicit `citation_info` packets are missing, leveraging the `final_documents` array in `message_start`.
|
|
33
|
+
- **Typewriter Synchronization**: Adjusted `MessageTextRenderer` to coordinate with the new turn-based completion logic, ensuring the UI remains interactive.
|
|
34
|
+
- **Logging & Observability**: Injected comprehensive tracing logs (`[RQ]`, `[sendMessage]`, `[MessageProcessor]`) to monitor the end-to-end flow of packets.
|
package/jest-addon.config.js
CHANGED
|
@@ -377,7 +377,7 @@ const getCoveragePatterns = () => {
|
|
|
377
377
|
arg === reserved || arg.startsWith(reserved.split('=')[0] + '='),
|
|
378
378
|
) &&
|
|
379
379
|
process.argv.indexOf(arg) >
|
|
380
|
-
|
|
380
|
+
process.argv.findIndex((item) => item === 'test'),
|
|
381
381
|
);
|
|
382
382
|
|
|
383
383
|
if (directoryArg) {
|
|
@@ -423,6 +423,7 @@ module.exports = {
|
|
|
423
423
|
'schema\\.[jt]s?$',
|
|
424
424
|
'index\\.[jt]s?$',
|
|
425
425
|
'config\\.[jt]sx?$',
|
|
426
|
+
'/types/',
|
|
426
427
|
],
|
|
427
428
|
moduleNameMapper: {
|
|
428
429
|
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { compose } from 'redux';
|
|
3
3
|
import superagent from 'superagent';
|
|
4
|
-
import
|
|
4
|
+
import SidebarPortal from '@plone/volto/components/manage/Sidebar/SidebarPortal';
|
|
5
|
+
import BlockDataForm from '@plone/volto/components/manage/Form/BlockDataForm';
|
|
5
6
|
|
|
6
7
|
import ChatBlockView from './ChatBlockView';
|
|
7
8
|
import { ChatBlockSchema } from './schema';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { ChatMessageProps } from '
|
|
1
|
+
import type { ChatMessageProps } from '@eeacms/volto-eea-chatbot/ChatBlock/types/interfaces';
|
|
2
2
|
import { useState, useMemo, useEffect } from 'react';
|
|
3
3
|
import cx from 'classnames';
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
import loadable from '@loadable/component';
|
|
6
6
|
import {
|
|
7
7
|
Tab,
|
|
@@ -14,27 +14,42 @@ import {
|
|
|
14
14
|
useDeepCompareMemoize,
|
|
15
15
|
useQualityMarkers,
|
|
16
16
|
useScrollonStream,
|
|
17
|
-
} from '
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
import
|
|
17
|
+
} from '@eeacms/volto-eea-chatbot/ChatBlock/hooks';
|
|
18
|
+
import {
|
|
19
|
+
MultiToolRenderer,
|
|
20
|
+
RendererComponent,
|
|
21
|
+
} from '@eeacms/volto-eea-chatbot/ChatBlock/packets';
|
|
22
|
+
import { addCitations } from '@eeacms/volto-eea-chatbot/ChatBlock/utils/citations';
|
|
23
|
+
import SVGIcon from '@eeacms/volto-eea-chatbot/ChatBlock/components/Icon';
|
|
24
|
+
import BotIcon from '@eeacms/volto-eea-chatbot/icons/bot.svg';
|
|
25
|
+
import ClearIcon from '@eeacms/volto-eea-chatbot/icons/clear.svg';
|
|
23
26
|
|
|
24
27
|
// Lazy load heavy components
|
|
25
|
-
const SourceDetails: any = loadable(
|
|
28
|
+
const SourceDetails: any = loadable(
|
|
29
|
+
() => import('@eeacms/volto-eea-chatbot/ChatBlock/components/Source'),
|
|
30
|
+
);
|
|
26
31
|
const UserActionsToolbar: any = loadable(
|
|
27
|
-
() =>
|
|
32
|
+
() =>
|
|
33
|
+
import('@eeacms/volto-eea-chatbot/ChatBlock/components/UserActionsToolbar'),
|
|
28
34
|
);
|
|
29
35
|
const RelatedQuestions: any = loadable(
|
|
30
|
-
() =>
|
|
36
|
+
() =>
|
|
37
|
+
import('@eeacms/volto-eea-chatbot/ChatBlock/components/RelatedQuestions'),
|
|
31
38
|
);
|
|
32
39
|
const HalloumiFeedback: any = loadable(
|
|
33
|
-
() =>
|
|
40
|
+
() =>
|
|
41
|
+
import('@eeacms/volto-eea-chatbot/ChatBlock/components/HalloumiFeedback'),
|
|
34
42
|
);
|
|
35
43
|
|
|
36
|
-
function
|
|
37
|
-
|
|
44
|
+
function visit(node: any, type: string, visitor: (node: any, idx?: number, parent?: any) => void, idx?: number, parent?: any) {
|
|
45
|
+
if (node.type === type) {
|
|
46
|
+
visitor(node, idx, parent);
|
|
47
|
+
}
|
|
48
|
+
if (node.children && Array.isArray(node.children)) {
|
|
49
|
+
node.children.forEach((child: any, cidx: number) => {
|
|
50
|
+
visit(child, type, visitor, cidx, node);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
38
53
|
}
|
|
39
54
|
|
|
40
55
|
function addQualityMarkersPlugin() {
|
|
@@ -316,8 +331,11 @@ export function AIMessage({
|
|
|
316
331
|
if (isFetchingRelatedQuestions || typeof relatedQuestions !== 'undefined') {
|
|
317
332
|
return;
|
|
318
333
|
}
|
|
319
|
-
if (
|
|
320
|
-
|
|
334
|
+
if (isLastMessage && isComplete && onFetchRelatedQuestions) {
|
|
335
|
+
console.log(`[AIMessage] Triggering RQ: messageDisplayed=${messageDisplayed}, isComplete=${isComplete}, hasContent=${!!message.message}`);
|
|
336
|
+
if (messageDisplayed) {
|
|
337
|
+
onFetchRelatedQuestions();
|
|
338
|
+
}
|
|
321
339
|
}
|
|
322
340
|
}, [
|
|
323
341
|
messageDisplayed,
|
|
@@ -325,6 +343,8 @@ export function AIMessage({
|
|
|
325
343
|
isComplete,
|
|
326
344
|
onFetchRelatedQuestions,
|
|
327
345
|
isFetchingRelatedQuestions,
|
|
346
|
+
isLastMessage,
|
|
347
|
+
message.message,
|
|
328
348
|
]);
|
|
329
349
|
|
|
330
350
|
useEffect(() => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Message as SemanticMessage } from 'semantic-ui-react';
|
|
2
|
-
import type { ChatMessageProps } from '
|
|
2
|
+
import type { ChatMessageProps } from '@eeacms/volto-eea-chatbot/ChatBlock/types/interfaces';
|
|
3
3
|
import { UserMessage, AIMessage } from '.';
|
|
4
4
|
|
|
5
5
|
export function ChatMessage(props: ChatMessageProps) {
|
|
@@ -5,21 +5,21 @@ import React, {
|
|
|
5
5
|
useMemo,
|
|
6
6
|
useCallback,
|
|
7
7
|
} from 'react';
|
|
8
|
-
import type { Persona } from '
|
|
8
|
+
import type { Persona } from '@eeacms/volto-eea-chatbot/ChatBlock/types/interfaces';
|
|
9
9
|
import { Button, Form, Segment, Checkbox } from 'semantic-ui-react';
|
|
10
10
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable';
|
|
11
11
|
import { trackEvent } from '@eeacms/volto-matomo/utils';
|
|
12
12
|
|
|
13
13
|
import { ChatMessage } from '.';
|
|
14
|
-
import { PacketType } from '
|
|
15
|
-
import AutoResizeTextarea from '
|
|
16
|
-
import QualityCheckToggle from '
|
|
17
|
-
import EmptyState from '
|
|
18
|
-
import { useChatController } from '
|
|
19
|
-
import SVGIcon from '
|
|
20
|
-
import PenIcon from '
|
|
14
|
+
import { PacketType } from '@eeacms/volto-eea-chatbot/ChatBlock/types/streamingModels';
|
|
15
|
+
import AutoResizeTextarea from '@eeacms/volto-eea-chatbot/ChatBlock/components/AutoResizeTextarea';
|
|
16
|
+
import QualityCheckToggle from '@eeacms/volto-eea-chatbot/ChatBlock/components/QualityCheckToggle';
|
|
17
|
+
import EmptyState from '@eeacms/volto-eea-chatbot/ChatBlock/components/EmptyState';
|
|
18
|
+
import { useChatController } from '@eeacms/volto-eea-chatbot/ChatBlock/hooks';
|
|
19
|
+
import SVGIcon from '@eeacms/volto-eea-chatbot/ChatBlock/components/Icon';
|
|
20
|
+
import PenIcon from '@eeacms/volto-eea-chatbot/icons/square-pen.svg';
|
|
21
21
|
|
|
22
|
-
import '
|
|
22
|
+
import '@eeacms/volto-eea-chatbot/ChatBlock/style.less';
|
|
23
23
|
|
|
24
24
|
interface ChatWindowProps {
|
|
25
25
|
block_id?: string;
|
|
@@ -48,6 +48,7 @@ interface ChatWindowProps {
|
|
|
48
48
|
enableMatomoTracking?: boolean;
|
|
49
49
|
onDemandInputToggle?: boolean;
|
|
50
50
|
maxContextSegments?: number;
|
|
51
|
+
onyxVersion?: '2' | '3';
|
|
51
52
|
isPlaywrightTest?: boolean;
|
|
52
53
|
[key: string]: any;
|
|
53
54
|
}
|
|
@@ -83,6 +84,7 @@ function ChatWindow({
|
|
|
83
84
|
enableMatomoTracking = true,
|
|
84
85
|
onDemandInputToggle = true,
|
|
85
86
|
maxContextSegments = 0,
|
|
87
|
+
onyxVersion = '2',
|
|
86
88
|
} = data;
|
|
87
89
|
const [qualityCheckEnabled, setQualityCheckEnabled] = useState(
|
|
88
90
|
onDemandInputToggle ?? true,
|
|
@@ -117,6 +119,7 @@ function ChatWindow({
|
|
|
117
119
|
qgenAsistantId,
|
|
118
120
|
enableQgen,
|
|
119
121
|
deepResearch,
|
|
122
|
+
onyxVersion,
|
|
120
123
|
});
|
|
121
124
|
|
|
122
125
|
const [showLandingPage, setShowLandingPage] = useState(true);
|
|
@@ -182,9 +185,8 @@ function ChatWindow({
|
|
|
182
185
|
style={{ maxHeight: height }}
|
|
183
186
|
>
|
|
184
187
|
{messages.map((message, index) => (
|
|
185
|
-
<React.Fragment>
|
|
188
|
+
<React.Fragment key={message.messageId}>
|
|
186
189
|
<ChatMessage
|
|
187
|
-
key={message.messageId}
|
|
188
190
|
prevMessage={messages[index - 1]}
|
|
189
191
|
message={message}
|
|
190
192
|
isLoading={isStreaming}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { ChatMessageProps } from '
|
|
1
|
+
import type { ChatMessageProps } from '@eeacms/volto-eea-chatbot/ChatBlock/types/interfaces';
|
|
2
2
|
import loadable from '@loadable/component';
|
|
3
|
-
import SVGIcon from '
|
|
4
|
-
import { components } from '
|
|
5
|
-
import UserIcon from '
|
|
3
|
+
import SVGIcon from '@eeacms/volto-eea-chatbot/ChatBlock/components/Icon';
|
|
4
|
+
import { components } from '@eeacms/volto-eea-chatbot/ChatBlock/components/markdown';
|
|
5
|
+
import UserIcon from '@eeacms/volto-eea-chatbot/icons/user.svg';
|
|
6
6
|
|
|
7
7
|
const Markdown: any = loadable(() => import('react-markdown'));
|
|
8
8
|
|
|
@@ -4,7 +4,7 @@ import { trackEvent } from '@eeacms/volto-matomo/utils';
|
|
|
4
4
|
import TextareaAutosize from 'react-textarea-autosize';
|
|
5
5
|
|
|
6
6
|
import SVGIcon from './Icon';
|
|
7
|
-
import SendIcon from '
|
|
7
|
+
import SendIcon from '@eeacms/volto-eea-chatbot/icons/send.svg';
|
|
8
8
|
|
|
9
9
|
export default React.forwardRef(function AutoResizeTextarea(props, ref) {
|
|
10
10
|
const { onSubmit, isStreaming, enableMatomoTracking, persona, ...rest } =
|
|
@@ -2,8 +2,8 @@ import { useState } from 'react';
|
|
|
2
2
|
import { Button, Icon } from 'semantic-ui-react';
|
|
3
3
|
import FeedbackModal from './FeedbackModal';
|
|
4
4
|
import SVGIcon from './Icon';
|
|
5
|
-
import ThumbsUpIcon from '
|
|
6
|
-
import ThumbsDownIcon from '
|
|
5
|
+
import ThumbsUpIcon from '@eeacms/volto-eea-chatbot/icons/thumbs-up.svg';
|
|
6
|
+
import ThumbsDownIcon from '@eeacms/volto-eea-chatbot/icons/thumbs-down.svg';
|
|
7
7
|
|
|
8
8
|
const Toast = ({ message, type, isActive }) => (
|
|
9
9
|
<div className={`feedback-toast ${type} ${isActive ? 'active' : ''}`}>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import { trackEvent } from '@eeacms/volto-matomo/utils';
|
|
3
3
|
import { Modal, Button, TextArea, Form, Icon } from 'semantic-ui-react';
|
|
4
|
-
import { createChatMessageFeedback } from '
|
|
4
|
+
import { createChatMessageFeedback } from '@eeacms/volto-eea-chatbot/ChatBlock/utils';
|
|
5
5
|
|
|
6
6
|
const FeedbackModal = ({
|
|
7
7
|
modalOpen,
|
|
@@ -6,8 +6,8 @@ import Spinner from './Spinner';
|
|
|
6
6
|
import SVGIcon from './Icon';
|
|
7
7
|
import { getSupportedBgColor } from './markdown/colors';
|
|
8
8
|
|
|
9
|
-
import GlassesIcon from '
|
|
10
|
-
import RotateIcon from '
|
|
9
|
+
import GlassesIcon from '@eeacms/volto-eea-chatbot/icons/glasses.svg';
|
|
10
|
+
import RotateIcon from '@eeacms/volto-eea-chatbot/icons/rotate.svg';
|
|
11
11
|
|
|
12
12
|
const VERIFY_CLAIM_MESSAGES = [
|
|
13
13
|
'Going through each claim and verify against the referenced documents...',
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Popup } from 'semantic-ui-react';
|
|
2
2
|
import SVGIcon from './Icon';
|
|
3
3
|
|
|
4
|
-
import FileIcon from '
|
|
5
|
-
import GlobeIcon from '
|
|
4
|
+
import FileIcon from '@eeacms/volto-eea-chatbot/icons/file.svg';
|
|
5
|
+
import GlobeIcon from '@eeacms/volto-eea-chatbot/icons/globe.svg';
|
|
6
6
|
|
|
7
7
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
8
8
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import cx from 'classnames';
|
|
2
2
|
import { Button } from 'semantic-ui-react';
|
|
3
|
-
import { useCopyToClipboard } from '
|
|
3
|
+
import { useCopyToClipboard } from '@eeacms/volto-eea-chatbot/ChatBlock/utils';
|
|
4
4
|
import SVGIcon from './Icon';
|
|
5
5
|
import ChatMessageFeedback from './ChatMessageFeedback';
|
|
6
6
|
|
|
7
|
-
import CopyIcon from '
|
|
8
|
-
import CheckIcon from '
|
|
7
|
+
import CopyIcon from '@eeacms/volto-eea-chatbot/icons/copy.svg';
|
|
8
|
+
import CheckIcon from '@eeacms/volto-eea-chatbot/icons/check.svg';
|
|
9
9
|
|
|
10
10
|
const UserActionsToolbar = ({
|
|
11
11
|
className,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
2
|
import SVGIcon from './Icon';
|
|
3
|
-
import FileIcon from '
|
|
4
|
-
import GlobeIcon from '
|
|
3
|
+
import FileIcon from '@eeacms/volto-eea-chatbot/icons/file.svg';
|
|
4
|
+
import GlobeIcon from '@eeacms/volto-eea-chatbot/icons/globe.svg';
|
|
5
5
|
|
|
6
6
|
interface WebResultIconProps {
|
|
7
7
|
url: string;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Modal, ModalContent, ModalHeader } from 'semantic-ui-react';
|
|
2
2
|
import cx from 'classnames';
|
|
3
|
-
import { convertToPercentage } from '
|
|
4
|
-
import SVGIcon from '
|
|
3
|
+
import { convertToPercentage } from '@eeacms/volto-eea-chatbot/ChatBlock/utils';
|
|
4
|
+
import SVGIcon from '@eeacms/volto-eea-chatbot/ChatBlock/components/Icon';
|
|
5
5
|
import { getSupportedBgColor } from './colors';
|
|
6
6
|
import { ClaimSegments } from './ClaimSegments';
|
|
7
7
|
|
|
8
|
-
import BotIcon from '
|
|
8
|
+
import BotIcon from '@eeacms/volto-eea-chatbot/icons/bot.svg';
|
|
9
9
|
|
|
10
10
|
const stripHtml = (html) => {
|
|
11
11
|
const tmp = document.createElement('div');
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Tab, TabPane } from 'semantic-ui-react';
|
|
3
|
-
import SVGIcon from '
|
|
3
|
+
import SVGIcon from '@eeacms/volto-eea-chatbot/ChatBlock/components/Icon';
|
|
4
4
|
import { RenderClaimView } from './RenderClaimView';
|
|
5
|
-
import LinkIcon from '
|
|
6
|
-
import FileIcon from '
|
|
7
|
-
import GlobeIcon from '
|
|
5
|
+
import LinkIcon from '@eeacms/volto-eea-chatbot/icons/external-link.svg';
|
|
6
|
+
import FileIcon from '@eeacms/volto-eea-chatbot/icons/file.svg';
|
|
7
|
+
import GlobeIcon from '@eeacms/volto-eea-chatbot/icons/globe.svg';
|
|
8
8
|
|
|
9
9
|
const VISIBLE_SEGMENTS = 50; // Number of citations to show by default
|
|
10
10
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ClaimModal } from './ClaimModal';
|
|
3
3
|
import { Citation } from './Citation';
|
|
4
|
-
import { transformEmailsToLinks } from '
|
|
4
|
+
import { transformEmailsToLinks } from '@eeacms/volto-eea-chatbot/ChatBlock/utils';
|
|
5
5
|
|
|
6
6
|
export function components(message, markers, citedSources) {
|
|
7
7
|
return {
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import type { Message } from '
|
|
1
|
+
import type { Message } from '@eeacms/volto-eea-chatbot/ChatBlock/types/interfaces';
|
|
2
2
|
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
3
3
|
import { useChatStreaming } from './useChatStreaming';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import {
|
|
5
|
+
createChatSession,
|
|
6
|
+
sendMessage,
|
|
7
|
+
} from '@eeacms/volto-eea-chatbot/ChatBlock/services/streamingService';
|
|
8
|
+
import { PacketType } from '@eeacms/volto-eea-chatbot/ChatBlock/types/streamingModels';
|
|
9
|
+
import { ResearchType } from '@eeacms/volto-eea-chatbot/ChatBlock/types/interfaces';
|
|
7
10
|
|
|
8
11
|
interface UseChatControllerProps {
|
|
9
12
|
personaId: number;
|
|
10
13
|
enableQgen?: boolean;
|
|
11
14
|
qgenAsistantId?: number;
|
|
12
15
|
deepResearch?: string;
|
|
16
|
+
onyxVersion?: '2' | '3';
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
interface RelatedQuestion {
|
|
@@ -18,14 +22,42 @@ interface RelatedQuestion {
|
|
|
18
22
|
|
|
19
23
|
// Extract JSON array from related questions response
|
|
20
24
|
function extractRelatedQuestions(str: string): RelatedQuestion[] {
|
|
21
|
-
if (str.toLowerCase().includes('no_response')) {
|
|
22
|
-
|
|
25
|
+
if (!str || str.toLowerCase().includes('no_response')) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Try to parse as JSON first if it looks like JSON
|
|
30
|
+
const trimmed = str.trim();
|
|
31
|
+
if (trimmed.startsWith('[') || trimmed.startsWith('{')) {
|
|
32
|
+
try {
|
|
33
|
+
const parsed = JSON.parse(trimmed);
|
|
34
|
+
const items = Array.isArray(parsed) ? parsed : parsed.questions || [];
|
|
35
|
+
if (Array.isArray(items)) {
|
|
36
|
+
return items
|
|
37
|
+
.map((item) => {
|
|
38
|
+
if (typeof item === 'string') return { question: item };
|
|
39
|
+
if (item && typeof item === 'object' && item.question)
|
|
40
|
+
return { question: item.question };
|
|
41
|
+
return null;
|
|
42
|
+
})
|
|
43
|
+
.filter((i): i is RelatedQuestion => i !== null);
|
|
44
|
+
}
|
|
45
|
+
} catch (e) {
|
|
46
|
+
// Fallback to line parsing
|
|
47
|
+
}
|
|
23
48
|
}
|
|
24
49
|
|
|
50
|
+
// Fallback: split by lines and clean up common list formats
|
|
25
51
|
return str
|
|
26
52
|
.split('\n')
|
|
27
|
-
.
|
|
28
|
-
.
|
|
53
|
+
.map((line) => line.trim())
|
|
54
|
+
.filter((line) => line.length > 0)
|
|
55
|
+
.map((line) => {
|
|
56
|
+
// Remove leading numbers or bullets like "1. ", "- ", "* ", etc.
|
|
57
|
+
const cleaned = line.replace(/^[\d\.\-\*\s]+/, '').trim();
|
|
58
|
+
return cleaned ? { question: cleaned } : null;
|
|
59
|
+
})
|
|
60
|
+
.filter((i): i is RelatedQuestion => i !== null);
|
|
29
61
|
}
|
|
30
62
|
|
|
31
63
|
// Fetch related questions using the qgen assistant
|
|
@@ -33,12 +65,16 @@ async function fetchRelatedQuestions(
|
|
|
33
65
|
query: string,
|
|
34
66
|
answer: string,
|
|
35
67
|
qgenAsistantId: number,
|
|
68
|
+
onyxVersion: '2' | '3' = '2',
|
|
36
69
|
): Promise<RelatedQuestion[]> {
|
|
37
70
|
try {
|
|
71
|
+
console.log(`[RQ] Creating session for assistant ${qgenAsistantId} (Onyx v${onyxVersion})`);
|
|
38
72
|
const chatSessionId = await createChatSession(
|
|
39
73
|
qgenAsistantId,
|
|
40
74
|
`Q: ${query}`,
|
|
75
|
+
true,
|
|
41
76
|
);
|
|
77
|
+
console.log(`[RQ] Session created: ${chatSessionId}`);
|
|
42
78
|
|
|
43
79
|
const params = {
|
|
44
80
|
message: `Question: ${query}\nAnswer:\n${answer}`,
|
|
@@ -46,23 +82,35 @@ async function fetchRelatedQuestions(
|
|
|
46
82
|
fileDescriptors: [],
|
|
47
83
|
parentMessageId: null,
|
|
48
84
|
chatSessionId,
|
|
49
|
-
promptId: 0,
|
|
50
85
|
filters: null,
|
|
51
86
|
selectedDocumentIds: [],
|
|
52
87
|
use_agentic_search: false,
|
|
53
88
|
regenerate: false,
|
|
89
|
+
onyxVersion,
|
|
54
90
|
};
|
|
55
91
|
|
|
92
|
+
if (onyxVersion === '3') {
|
|
93
|
+
console.log('[Onyx v3] Sending RQ prompt:', params.message);
|
|
94
|
+
}
|
|
95
|
+
|
|
56
96
|
let result = '';
|
|
57
97
|
for await (const packets of sendMessage(params, true)) {
|
|
58
98
|
for (const packet of packets) {
|
|
59
|
-
if (
|
|
60
|
-
|
|
99
|
+
if (onyxVersion === '3') {
|
|
100
|
+
// console.log('[Onyx v3] RQ Packet:', packet);
|
|
101
|
+
}
|
|
102
|
+
if (
|
|
103
|
+
packet.obj.type === PacketType.MESSAGE_DELTA ||
|
|
104
|
+
packet.obj.type === PacketType.MESSAGE_START
|
|
105
|
+
) {
|
|
106
|
+
result += (packet.obj as any).content || '';
|
|
61
107
|
}
|
|
62
108
|
}
|
|
63
109
|
}
|
|
64
|
-
|
|
65
|
-
|
|
110
|
+
console.log(`[RQ] Final response string: "${result}"`);
|
|
111
|
+
const extracted = extractRelatedQuestions(result);
|
|
112
|
+
console.log(`[RQ] Extracted ${extracted.length} questions`);
|
|
113
|
+
return extracted;
|
|
66
114
|
} catch (error) {
|
|
67
115
|
console.error('Error fetching related questions:', error);
|
|
68
116
|
return [];
|
|
@@ -74,6 +122,7 @@ export function useChatController({
|
|
|
74
122
|
enableQgen = false,
|
|
75
123
|
qgenAsistantId,
|
|
76
124
|
deepResearch,
|
|
125
|
+
onyxVersion = '2',
|
|
77
126
|
}: UseChatControllerProps) {
|
|
78
127
|
const [messages, setMessages] = useState<Message[]>([]);
|
|
79
128
|
const [chatSessionId, setChatSessionId] = useState<string | null>(null);
|
|
@@ -226,6 +275,7 @@ export function useChatController({
|
|
|
226
275
|
regenerate: false,
|
|
227
276
|
filters: null,
|
|
228
277
|
selectedDocumentIds: [],
|
|
278
|
+
onyxVersion,
|
|
229
279
|
},
|
|
230
280
|
assistantNodeId,
|
|
231
281
|
userNodeId,
|
|
@@ -247,6 +297,7 @@ export function useChatController({
|
|
|
247
297
|
);
|
|
248
298
|
|
|
249
299
|
const onFetchRelatedQuestions = useCallback(async () => {
|
|
300
|
+
console.log('[RQ] onFetchRelatedQuestions triggered');
|
|
250
301
|
const latestAssistantMessage = messages
|
|
251
302
|
.filter((m) => m.type === 'assistant')
|
|
252
303
|
.pop();
|
|
@@ -256,6 +307,7 @@ export function useChatController({
|
|
|
256
307
|
qgenAsistantId &&
|
|
257
308
|
latestAssistantMessage?.type === 'assistant'
|
|
258
309
|
) {
|
|
310
|
+
console.log(`[RQ] Criteria met: assistantNodeId=${latestAssistantMessage.nodeId}, qgenAssistant=${qgenAsistantId}`);
|
|
259
311
|
if (isDeepResearchEnabled) {
|
|
260
312
|
setMessages((prev) => {
|
|
261
313
|
return prev.map((m) =>
|
|
@@ -281,6 +333,7 @@ export function useChatController({
|
|
|
281
333
|
userMessage.message,
|
|
282
334
|
latestAssistantMessage.message,
|
|
283
335
|
qgenAsistantId,
|
|
336
|
+
onyxVersion,
|
|
284
337
|
);
|
|
285
338
|
}
|
|
286
339
|
} catch (error) {
|
|
@@ -296,7 +349,7 @@ export function useChatController({
|
|
|
296
349
|
setIsFetchingRelatedQuestions(false);
|
|
297
350
|
}
|
|
298
351
|
}
|
|
299
|
-
}, [messages, enableQgen, qgenAsistantId, isDeepResearchEnabled]);
|
|
352
|
+
}, [messages, enableQgen, qgenAsistantId, isDeepResearchEnabled, onyxVersion]);
|
|
300
353
|
|
|
301
354
|
const clearChat = useCallback(() => {
|
|
302
355
|
setMessages([]);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { Message } from '
|
|
2
|
-
import type { SendMessageParams } from '
|
|
1
|
+
import type { Message } from '@eeacms/volto-eea-chatbot/ChatBlock/types/interfaces';
|
|
2
|
+
import type { SendMessageParams } from '@eeacms/volto-eea-chatbot/ChatBlock/services/streamingService';
|
|
3
3
|
import { useState, useCallback, useRef } from 'react';
|
|
4
|
-
import { sendMessage } from '
|
|
5
|
-
import { MessageProcessor } from '
|
|
4
|
+
import { sendMessage } from '@eeacms/volto-eea-chatbot/ChatBlock/services/streamingService';
|
|
5
|
+
import { MessageProcessor } from '@eeacms/volto-eea-chatbot/ChatBlock/services/messageProcessor';
|
|
6
6
|
|
|
7
7
|
interface UseChatStreamingProps {
|
|
8
8
|
onMessageUpdate?: (message: Message, processor: MessageProcessor) => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Packet } from '
|
|
1
|
+
import type { Packet } from '@eeacms/volto-eea-chatbot/ChatBlock/types/streamingModels';
|
|
2
2
|
import { useMemo, useState, useCallback, useEffect } from 'react';
|
|
3
3
|
|
|
4
4
|
interface ToolState {
|
|
@@ -76,5 +76,6 @@ export function useToolDisplayTiming(
|
|
|
76
76
|
visibleTools,
|
|
77
77
|
handleToolComplete,
|
|
78
78
|
allToolsDisplayed,
|
|
79
|
+
toolStates,
|
|
79
80
|
};
|
|
80
81
|
}
|