@coveo/quantic 3.42.1 → 3.43.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/force-app/main/default/labels/CustomLabels.labels-meta.xml +21 -0
- package/force-app/main/default/lwc/quanticGeneratedAnswer/__tests__/quanticGeneratedAnswer.test.js +145 -60
- package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/agentData.ts +248 -0
- package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/fixture-agent.ts +77 -0
- package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/fixture.ts +74 -65
- package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/pageObject.ts +157 -15
- package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/quanticGeneratedAnswer.e2e.ts +1 -5
- package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/quanticGeneratedAnswerAgent.e2e.ts +233 -0
- package/force-app/main/default/lwc/quanticGeneratedAnswer/quanticGeneratedAnswer.js +12 -108
- package/force-app/main/default/lwc/quanticGeneratedAnswer/templates/conversation.html +1 -1
- package/force-app/main/default/lwc/quanticGeneratedAnswer/templates/generatedAnswer.html +8 -47
- package/force-app/main/default/lwc/quanticGeneratedAnswerContent/__tests__/quanticGeneratedAnswerContent.test.js +27 -0
- package/force-app/main/default/lwc/quanticGeneratedAnswerContent/quanticGeneratedAnswerContent.js +8 -1
- package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/__tests__/quanticGeneratedAnswerFollowUpInput.test.js +242 -10
- package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/quanticGeneratedAnswerFollowUpInput.css +2 -2
- package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/quanticGeneratedAnswerFollowUpInput.html +16 -1
- package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/quanticGeneratedAnswerFollowUpInput.js +47 -4
- package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/__tests__/quanticGeneratedAnswerStreamOfThought.test.js +95 -41
- package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/__tests__/stepsUtils.test.js +118 -0
- package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/quanticGeneratedAnswerStreamOfThought.js +21 -35
- package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/stepsUtils.js +66 -0
- package/force-app/main/default/staticresources/coveoheadless/case-assist/headless.js +15 -15
- package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/product-listing/facets/headless-product-listing-facet-options.d.ts +4 -39
- package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/search/facets/headless-search-facet-options.d.ts +4 -39
- package/force-app/main/default/staticresources/coveoheadless/definitions/features/commerce/facets/facet-set/facet-set-selector.d.ts +3 -9
- package/force-app/main/default/staticresources/coveoheadless/definitions/features/facets/facet-search-set/category/category-facet-search-state-selector.d.ts +1 -27
- package/force-app/main/default/staticresources/coveoheadless/definitions/features/facets/facet-search-set/specific/specific-facet-search-state-selector.d.ts +1 -27
- package/force-app/main/default/staticresources/coveoheadless/headless.js +17 -17
- package/force-app/main/default/staticresources/coveoheadless/insight/headless.js +16 -16
- package/force-app/main/default/staticresources/coveoheadless/recommendation/headless.js +14 -14
- package/force-app/main/default/staticresources/dompurify/purify.min.js +2 -2
- package/package.json +7 -6
|
@@ -1652,6 +1652,13 @@
|
|
|
1652
1652
|
<protected>false</protected>
|
|
1653
1653
|
<shortDescription>Submit follow-up</shortDescription>
|
|
1654
1654
|
</labels>
|
|
1655
|
+
<labels>
|
|
1656
|
+
<fullName>quantic_FollowUpInputTooLong</fullName>
|
|
1657
|
+
<value>Your question is too long. Please use {{0}} characters or fewer.</value>
|
|
1658
|
+
<language>en_US</language>
|
|
1659
|
+
<protected>false</protected>
|
|
1660
|
+
<shortDescription>Follow-up question character limit exceeded</shortDescription>
|
|
1661
|
+
</labels>
|
|
1655
1662
|
<labels>
|
|
1656
1663
|
<fullName>quantic_ShowPreviousQuestions_plural</fullName>
|
|
1657
1664
|
<value>Show {{0}} previous questions</value>
|
|
@@ -1687,6 +1694,20 @@
|
|
|
1687
1694
|
<protected>false</protected>
|
|
1688
1695
|
<shortDescription>Knowledge base searched</shortDescription>
|
|
1689
1696
|
</labels>
|
|
1697
|
+
<labels>
|
|
1698
|
+
<fullName>quantic_AgentGenerationStepSearchQuery</fullName>
|
|
1699
|
+
<value>Searching for {{0}}…</value>
|
|
1700
|
+
<language>en_US</language>
|
|
1701
|
+
<protected>false</protected>
|
|
1702
|
+
<shortDescription>Searching for query</shortDescription>
|
|
1703
|
+
</labels>
|
|
1704
|
+
<labels>
|
|
1705
|
+
<fullName>quantic_AgentGenerationStepSearchQueryCompleted</fullName>
|
|
1706
|
+
<value>Searched for {{0}}</value>
|
|
1707
|
+
<language>en_US</language>
|
|
1708
|
+
<protected>false</protected>
|
|
1709
|
+
<shortDescription>Searched for query</shortDescription>
|
|
1710
|
+
</labels>
|
|
1690
1711
|
<labels>
|
|
1691
1712
|
<fullName>quantic_AgentGenerationStepAnalyzingResults</fullName>
|
|
1692
1713
|
<value>Analyzing results…</value>
|
package/force-app/main/default/lwc/quanticGeneratedAnswer/__tests__/quanticGeneratedAnswer.test.js
CHANGED
|
@@ -89,9 +89,8 @@ const selectors = {
|
|
|
89
89
|
generatedAnswer: '[data-testid="generated-answer__answer"]',
|
|
90
90
|
generatedAnswerBadge: '[data-testid="generated-answer__header-title"]',
|
|
91
91
|
generatedAnswerRetryButton: '[data-testid="generated-answer__retry-button"]',
|
|
92
|
-
generatedAnswerActions: '[data-testid="generated-answer__actions"]',
|
|
93
92
|
generatedAnswerToggleButton: 'c-quantic-generated-answer-toggle',
|
|
94
|
-
|
|
93
|
+
generatedAnswerBodyComponent: 'c-quantic-generated-answer-body',
|
|
95
94
|
generatingMessageWhenAnswerCollapsed:
|
|
96
95
|
'[data-testid="generated-answer__collapse-generating-message"]',
|
|
97
96
|
generatedAnswerCollapseToggle:
|
|
@@ -101,10 +100,8 @@ const selectors = {
|
|
|
101
100
|
'[data-testid="generated-answer__no-answer-card"]',
|
|
102
101
|
generatedAnswerNoAnswerMessage:
|
|
103
102
|
'[data-testid="generated-answer__no-answer-message"]',
|
|
104
|
-
generatedAnswerCitations: 'c-quantic-source-citations',
|
|
105
103
|
generatedAnswerThread: 'c-quantic-generated-answer-thread',
|
|
106
104
|
generatedAnswerFollowUpInput: 'c-quantic-generated-answer-follow-up-input',
|
|
107
|
-
generatedAnswerFeedback: 'c-quantic-feedback',
|
|
108
105
|
loadingSpinner: 'lightning-spinner',
|
|
109
106
|
};
|
|
110
107
|
|
|
@@ -128,6 +125,7 @@ const functionsMocks = {
|
|
|
128
125
|
like: functionsMocks.like,
|
|
129
126
|
dislike: functionsMocks.dislike,
|
|
130
127
|
closeFeedbackModal: functionsMocks.closeFeedbackModal,
|
|
128
|
+
logCitationHover: functionsMocks.logCitationHover,
|
|
131
129
|
})),
|
|
132
130
|
buildSearchStatus: jest.fn(() => ({
|
|
133
131
|
state: searchStatusState,
|
|
@@ -148,6 +146,7 @@ const functionsMocks = {
|
|
|
148
146
|
like: jest.fn(),
|
|
149
147
|
dislike: jest.fn(),
|
|
150
148
|
closeFeedbackModal: jest.fn(),
|
|
149
|
+
logCitationHover: jest.fn(),
|
|
151
150
|
};
|
|
152
151
|
|
|
153
152
|
/**
|
|
@@ -504,33 +503,25 @@ describe('c-quantic-generated-answer', () => {
|
|
|
504
503
|
});
|
|
505
504
|
});
|
|
506
505
|
|
|
507
|
-
it('should
|
|
506
|
+
it('should forward the streaming answer to the generated answer body', async () => {
|
|
508
507
|
const element = createTestComponent();
|
|
509
508
|
await flushPromises();
|
|
510
509
|
|
|
511
|
-
const
|
|
512
|
-
selectors.
|
|
513
|
-
);
|
|
514
|
-
|
|
515
|
-
expect(generatedAnswerContent).not.toBeNull();
|
|
516
|
-
expect(generatedAnswerContent.isStreaming).toBe(true);
|
|
517
|
-
expect(generatedAnswerContent.answer).toBe(exampleAnswer);
|
|
518
|
-
expect(generatedAnswerContent.answerContentFormat).toBe(
|
|
519
|
-
exampleAnswerContentFormat
|
|
510
|
+
const generatedAnswerBody = element.shadowRoot.querySelector(
|
|
511
|
+
selectors.generatedAnswerBodyComponent
|
|
520
512
|
);
|
|
521
|
-
expect(generatedAnswerContent.engineId).toBe(exampleEngineId);
|
|
522
|
-
expect(generatedAnswerContent.answerId).toBe(exampleAnswerId);
|
|
523
|
-
});
|
|
524
|
-
|
|
525
|
-
it('should not display the generated answer actions', async () => {
|
|
526
|
-
const element = createTestComponent();
|
|
527
|
-
await flushPromises();
|
|
528
513
|
|
|
529
|
-
|
|
530
|
-
|
|
514
|
+
expect(generatedAnswerBody).not.toBeNull();
|
|
515
|
+
expect(generatedAnswerBody.engineId).toBe(exampleEngineId);
|
|
516
|
+
expect(generatedAnswerBody.disableCitationAnchoring).toBe(false);
|
|
517
|
+
expect(generatedAnswerBody.generatedAnswer).toEqual(
|
|
518
|
+
expect.objectContaining({
|
|
519
|
+
answer: exampleAnswer,
|
|
520
|
+
answerContentFormat: exampleAnswerContentFormat,
|
|
521
|
+
answerId: exampleAnswerId,
|
|
522
|
+
isStreaming: true,
|
|
523
|
+
})
|
|
531
524
|
);
|
|
532
|
-
|
|
533
|
-
expect(generatedAnswerActions).toBeNull();
|
|
534
525
|
});
|
|
535
526
|
|
|
536
527
|
it('should not display the generated answer disclaimer in the footer', async () => {
|
|
@@ -769,38 +760,48 @@ describe('c-quantic-generated-answer', () => {
|
|
|
769
760
|
});
|
|
770
761
|
});
|
|
771
762
|
|
|
772
|
-
it('should
|
|
763
|
+
it('should forward the ready answer with citations to the generated answer body', async () => {
|
|
773
764
|
const element = createTestComponent();
|
|
774
765
|
await flushPromises();
|
|
775
766
|
|
|
776
|
-
const
|
|
777
|
-
selectors.
|
|
767
|
+
const generatedAnswerBody = element.shadowRoot.querySelector(
|
|
768
|
+
selectors.generatedAnswerBodyComponent
|
|
778
769
|
);
|
|
779
770
|
|
|
780
|
-
expect(
|
|
781
|
-
expect(
|
|
782
|
-
expect(
|
|
783
|
-
expect(
|
|
784
|
-
|
|
771
|
+
expect(generatedAnswerBody).not.toBeNull();
|
|
772
|
+
expect(generatedAnswerBody.engineId).toBe(exampleEngineId);
|
|
773
|
+
expect(generatedAnswerBody.disableCitationAnchoring).toBe(false);
|
|
774
|
+
expect(generatedAnswerBody.generatedAnswer).toEqual(
|
|
775
|
+
expect.objectContaining({
|
|
776
|
+
answer: exampleAnswer,
|
|
777
|
+
answerContentFormat: exampleAnswerContentFormat,
|
|
778
|
+
citations: exampleCitations,
|
|
779
|
+
isStreaming: false,
|
|
780
|
+
})
|
|
785
781
|
);
|
|
786
782
|
});
|
|
787
783
|
|
|
788
|
-
it('should
|
|
789
|
-
const element = createTestComponent(
|
|
784
|
+
it('should collapse the answer when the body reports a content height exceeding the maximum collapsed height', async () => {
|
|
785
|
+
const element = createTestComponent({
|
|
786
|
+
...defaultOptions,
|
|
787
|
+
collapsible: true,
|
|
788
|
+
});
|
|
790
789
|
await flushPromises();
|
|
791
790
|
|
|
792
791
|
const generatedAnswerBody = element.shadowRoot.querySelector(
|
|
793
|
-
selectors.
|
|
792
|
+
selectors.generatedAnswerBodyComponent
|
|
794
793
|
);
|
|
795
|
-
|
|
796
|
-
|
|
794
|
+
generatedAnswerBody.dispatchEvent(
|
|
795
|
+
new CustomEvent('quantic__answercontentupdated', {
|
|
796
|
+
detail: {height: defaultAnswerHeight + 100},
|
|
797
|
+
})
|
|
797
798
|
);
|
|
799
|
+
await flushPromises();
|
|
798
800
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
expect(generatedAnswerActions.closest('section')).toBe(
|
|
802
|
-
generatedAnswerBody
|
|
801
|
+
const generatedAnswerCollapseToggle = element.shadowRoot.querySelector(
|
|
802
|
+
selectors.generatedAnswerCollapseToggle
|
|
803
803
|
);
|
|
804
|
+
expect(generatedAnswerCollapseToggle).not.toBeNull();
|
|
804
805
|
});
|
|
805
806
|
|
|
806
807
|
it('should display the generated answer disclaimer', async () => {
|
|
@@ -833,17 +834,6 @@ describe('c-quantic-generated-answer', () => {
|
|
|
833
834
|
expect(generatedAnswerBadge).not.toBeNull();
|
|
834
835
|
});
|
|
835
836
|
|
|
836
|
-
it('should pass the disableCitationAnchoring property to the source citations component', async () => {
|
|
837
|
-
const element = createTestComponent();
|
|
838
|
-
await flushPromises();
|
|
839
|
-
|
|
840
|
-
const generatedAnswerCitations = element.shadowRoot.querySelector(
|
|
841
|
-
selectors.generatedAnswerCitations
|
|
842
|
-
);
|
|
843
|
-
expect(generatedAnswerCitations).not.toBeNull();
|
|
844
|
-
expect(generatedAnswerCitations.disableCitationAnchoring).toBe(false);
|
|
845
|
-
});
|
|
846
|
-
|
|
847
837
|
describe('when follow-ups are enabled', () => {
|
|
848
838
|
const exampleAgentId = 'example agent id';
|
|
849
839
|
const exampleFollowUpAnswers = [
|
|
@@ -1385,6 +1375,103 @@ describe('c-quantic-generated-answer', () => {
|
|
|
1385
1375
|
});
|
|
1386
1376
|
});
|
|
1387
1377
|
|
|
1378
|
+
describe('the citation hover event', () => {
|
|
1379
|
+
const exampleAnswer = 'answer generated successfully';
|
|
1380
|
+
const exampleAgentId = 'example agent id';
|
|
1381
|
+
const exampleCitationId = 'citation-id-1';
|
|
1382
|
+
const exampleCitationHoverTimeMs = 1500;
|
|
1383
|
+
|
|
1384
|
+
describe('when follow-ups are not enabled', () => {
|
|
1385
|
+
beforeEach(() => {
|
|
1386
|
+
generatedAnswerState = {
|
|
1387
|
+
...initialGeneratedAnswerState,
|
|
1388
|
+
isStreaming: false,
|
|
1389
|
+
answer: exampleAnswer,
|
|
1390
|
+
answerContentFormat: 'text/markdown',
|
|
1391
|
+
answerId: exampleAnswerId,
|
|
1392
|
+
citations: exampleCitations,
|
|
1393
|
+
};
|
|
1394
|
+
mockSuccessfulHeadlessInitialization();
|
|
1395
|
+
prepareHeadlessState();
|
|
1396
|
+
});
|
|
1397
|
+
|
|
1398
|
+
afterAll(() => {
|
|
1399
|
+
generatedAnswerState = initialGeneratedAnswerState;
|
|
1400
|
+
});
|
|
1401
|
+
|
|
1402
|
+
it('should call logCitationHover on the controller with the correct parameters', async () => {
|
|
1403
|
+
const element = createTestComponent();
|
|
1404
|
+
await flushPromises();
|
|
1405
|
+
|
|
1406
|
+
const generatedAnswerBody = element.shadowRoot.querySelector(
|
|
1407
|
+
selectors.generatedAnswerBodyComponent
|
|
1408
|
+
);
|
|
1409
|
+
generatedAnswerBody.dispatchEvent(
|
|
1410
|
+
new CustomEvent('quantic__citationhover', {
|
|
1411
|
+
detail: {
|
|
1412
|
+
citationId: exampleCitationId,
|
|
1413
|
+
citationHoverTimeMs: exampleCitationHoverTimeMs,
|
|
1414
|
+
answerId: exampleAnswerId,
|
|
1415
|
+
},
|
|
1416
|
+
})
|
|
1417
|
+
);
|
|
1418
|
+
await flushPromises();
|
|
1419
|
+
|
|
1420
|
+
expect(functionsMocks.logCitationHover).toHaveBeenCalledTimes(1);
|
|
1421
|
+
expect(functionsMocks.logCitationHover).toHaveBeenCalledWith(
|
|
1422
|
+
exampleCitationId,
|
|
1423
|
+
exampleCitationHoverTimeMs,
|
|
1424
|
+
exampleAnswerId
|
|
1425
|
+
);
|
|
1426
|
+
});
|
|
1427
|
+
});
|
|
1428
|
+
|
|
1429
|
+
describe('when follow-ups are enabled', () => {
|
|
1430
|
+
beforeEach(() => {
|
|
1431
|
+
generatedAnswerState = {
|
|
1432
|
+
...initialGeneratedAnswerState,
|
|
1433
|
+
answer: exampleAnswer,
|
|
1434
|
+
followUpAnswers: {isEnabled: true, followUpAnswers: []},
|
|
1435
|
+
};
|
|
1436
|
+
mockSuccessfulHeadlessInitialization();
|
|
1437
|
+
prepareHeadlessState();
|
|
1438
|
+
});
|
|
1439
|
+
|
|
1440
|
+
afterAll(() => {
|
|
1441
|
+
generatedAnswerState = initialGeneratedAnswerState;
|
|
1442
|
+
});
|
|
1443
|
+
|
|
1444
|
+
it('should call logCitationHover on the controller with the correct parameters', async () => {
|
|
1445
|
+
const element = createTestComponent({
|
|
1446
|
+
...defaultOptions,
|
|
1447
|
+
agentId: exampleAgentId,
|
|
1448
|
+
});
|
|
1449
|
+
await flushPromises();
|
|
1450
|
+
|
|
1451
|
+
const thread = element.shadowRoot.querySelector(
|
|
1452
|
+
selectors.generatedAnswerThread
|
|
1453
|
+
);
|
|
1454
|
+
thread.dispatchEvent(
|
|
1455
|
+
new CustomEvent('quantic__citationhover', {
|
|
1456
|
+
detail: {
|
|
1457
|
+
citationId: exampleCitationId,
|
|
1458
|
+
citationHoverTimeMs: exampleCitationHoverTimeMs,
|
|
1459
|
+
answerId: exampleAnswerId,
|
|
1460
|
+
},
|
|
1461
|
+
})
|
|
1462
|
+
);
|
|
1463
|
+
await flushPromises();
|
|
1464
|
+
|
|
1465
|
+
expect(functionsMocks.logCitationHover).toHaveBeenCalledTimes(1);
|
|
1466
|
+
expect(functionsMocks.logCitationHover).toHaveBeenCalledWith(
|
|
1467
|
+
exampleCitationId,
|
|
1468
|
+
exampleCitationHoverTimeMs,
|
|
1469
|
+
exampleAnswerId
|
|
1470
|
+
);
|
|
1471
|
+
});
|
|
1472
|
+
});
|
|
1473
|
+
});
|
|
1474
|
+
|
|
1388
1475
|
describe('the generated answer feedback', () => {
|
|
1389
1476
|
const exampleAnswer = 'answer generated successfully';
|
|
1390
1477
|
const exampleAgentId = 'example agent id';
|
|
@@ -1392,19 +1479,17 @@ describe('c-quantic-generated-answer', () => {
|
|
|
1392
1479
|
describe.each([
|
|
1393
1480
|
{
|
|
1394
1481
|
action: 'like',
|
|
1395
|
-
feedbackEvent: 'quantic__like',
|
|
1396
1482
|
threadEvent: 'quantic__generatedanswerlike',
|
|
1397
1483
|
controllerMethod: 'like',
|
|
1398
1484
|
},
|
|
1399
1485
|
{
|
|
1400
1486
|
action: 'dislike',
|
|
1401
|
-
feedbackEvent: 'quantic__dislike',
|
|
1402
1487
|
threadEvent: 'quantic__generatedanswerdislike',
|
|
1403
1488
|
controllerMethod: 'dislike',
|
|
1404
1489
|
},
|
|
1405
1490
|
])(
|
|
1406
1491
|
'when the user clicks the $action button',
|
|
1407
|
-
({
|
|
1492
|
+
({threadEvent, controllerMethod}) => {
|
|
1408
1493
|
describe('when follow-ups are not enabled', () => {
|
|
1409
1494
|
beforeEach(() => {
|
|
1410
1495
|
generatedAnswerState = {
|
|
@@ -1427,11 +1512,11 @@ describe('c-quantic-generated-answer', () => {
|
|
|
1427
1512
|
const element = createTestComponent();
|
|
1428
1513
|
await flushPromises();
|
|
1429
1514
|
|
|
1430
|
-
const
|
|
1431
|
-
selectors.
|
|
1515
|
+
const generatedAnswerBody = element.shadowRoot.querySelector(
|
|
1516
|
+
selectors.generatedAnswerBodyComponent
|
|
1432
1517
|
);
|
|
1433
|
-
|
|
1434
|
-
new CustomEvent(
|
|
1518
|
+
generatedAnswerBody.dispatchEvent(
|
|
1519
|
+
new CustomEvent(threadEvent, {
|
|
1435
1520
|
detail: {answerId: exampleAnswerId},
|
|
1436
1521
|
})
|
|
1437
1522
|
);
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
type AgentRunType = {
|
|
2
|
+
type: 'RUN_STARTED' | 'RUN_FINISHED';
|
|
3
|
+
timestamp: number;
|
|
4
|
+
threadId: string;
|
|
5
|
+
runId: string;
|
|
6
|
+
result?: {
|
|
7
|
+
completionReason: string;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type AgentCustomType = {
|
|
12
|
+
type: 'CUSTOM';
|
|
13
|
+
timestamp: number;
|
|
14
|
+
name: string;
|
|
15
|
+
value: any;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type AgentStepType = {
|
|
19
|
+
type: 'STEP_STARTED' | 'STEP_FINISHED';
|
|
20
|
+
timestamp: number;
|
|
21
|
+
stepName: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type AgentToolCallType = {
|
|
25
|
+
type: 'TOOL_CALL_START' | 'TOOL_CALL_END';
|
|
26
|
+
timestamp: number;
|
|
27
|
+
toolCallId: string;
|
|
28
|
+
toolCallName: string;
|
|
29
|
+
parentMessageId: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type AgentToolCallArgsType = {
|
|
33
|
+
type: 'TOOL_CALL_ARGS';
|
|
34
|
+
timestamp: number;
|
|
35
|
+
toolCallId: string;
|
|
36
|
+
delta: any;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
type AgentTextMessageType = {
|
|
40
|
+
type: 'TEXT_MESSAGE_CHUNK';
|
|
41
|
+
timestamp: number;
|
|
42
|
+
messageId: string;
|
|
43
|
+
parentMessageId: string;
|
|
44
|
+
delta: string;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type AgentCitation = {
|
|
48
|
+
id: string;
|
|
49
|
+
title: string;
|
|
50
|
+
uri: string;
|
|
51
|
+
permanentid: string;
|
|
52
|
+
primaryId: string;
|
|
53
|
+
clickUri: string;
|
|
54
|
+
text: string;
|
|
55
|
+
source: string;
|
|
56
|
+
filetype: string;
|
|
57
|
+
fields: Record<string, any>;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
type AgentCitationType = {
|
|
61
|
+
type: 'CUSTOM';
|
|
62
|
+
timestamp: number;
|
|
63
|
+
name: 'citations';
|
|
64
|
+
value: {
|
|
65
|
+
citations: Array<AgentCitation>;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const STREAM_ID = 'conv_1';
|
|
70
|
+
const ANSWER_ID_1 = 'conv_1_0001';
|
|
71
|
+
const ANSWER_ID_2 = 'conv_1_0002';
|
|
72
|
+
const ANSWER_ID_3 = 'conv_1_0003';
|
|
73
|
+
const CONVERSATION_TOKEN = 'conv_1_token';
|
|
74
|
+
|
|
75
|
+
const runStartStream = (answerId: string): AgentRunType => ({
|
|
76
|
+
type: 'RUN_STARTED',
|
|
77
|
+
timestamp: new Date().valueOf(),
|
|
78
|
+
threadId: STREAM_ID,
|
|
79
|
+
runId: answerId,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const customInitialHeadersStream = (followUpEnabled: boolean): AgentCustomType => ({
|
|
83
|
+
type: 'CUSTOM',
|
|
84
|
+
timestamp: new Date().valueOf(),
|
|
85
|
+
name: 'header',
|
|
86
|
+
value: {
|
|
87
|
+
contentFormat: 'text/markdown',
|
|
88
|
+
conversationId: STREAM_ID,
|
|
89
|
+
followUpEnabled,
|
|
90
|
+
conversationToken: CONVERSATION_TOKEN,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const stepStartedStream = (stepName: string): AgentStepType => ({
|
|
95
|
+
type: 'STEP_STARTED',
|
|
96
|
+
timestamp: new Date().valueOf(),
|
|
97
|
+
stepName,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const stepFinishedStream = (stepName: string): AgentStepType => ({
|
|
101
|
+
type: 'STEP_FINISHED',
|
|
102
|
+
timestamp: new Date().valueOf(),
|
|
103
|
+
stepName,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const toolCallStartStream = (toolCallName: string): AgentToolCallType => ({
|
|
107
|
+
type: 'TOOL_CALL_START',
|
|
108
|
+
timestamp: new Date().valueOf(),
|
|
109
|
+
toolCallId: 'tool_call_1',
|
|
110
|
+
toolCallName,
|
|
111
|
+
parentMessageId: 'message_1',
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const searchQueryToolCallArgsStream = (q: string): AgentToolCallArgsType => ({
|
|
115
|
+
type: 'TOOL_CALL_ARGS',
|
|
116
|
+
timestamp: new Date().valueOf(),
|
|
117
|
+
toolCallId: 'tool_call_1',
|
|
118
|
+
delta: JSON.stringify({
|
|
119
|
+
q,
|
|
120
|
+
}),
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const toolCallEndStream = (toolCallName: string): AgentToolCallType => ({
|
|
124
|
+
type: 'TOOL_CALL_END',
|
|
125
|
+
timestamp: new Date().valueOf(),
|
|
126
|
+
toolCallId: 'tool_call_1',
|
|
127
|
+
toolCallName,
|
|
128
|
+
parentMessageId: 'message_1',
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const textMessageStream = (delta: string): AgentTextMessageType => ({
|
|
132
|
+
type: 'TEXT_MESSAGE_CHUNK',
|
|
133
|
+
timestamp: new Date().valueOf(),
|
|
134
|
+
messageId: 'message_2',
|
|
135
|
+
parentMessageId: 'message_1',
|
|
136
|
+
delta,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const exampleCitation: AgentCitation = {
|
|
140
|
+
id: 'some-id-1',
|
|
141
|
+
title: 'Some Title 1',
|
|
142
|
+
uri: 'https://www.coveo.com',
|
|
143
|
+
permanentid: 'some-permanent-id-1',
|
|
144
|
+
clickUri: 'https://www.coveo.com',
|
|
145
|
+
text: 'example text 1',
|
|
146
|
+
source: 'Some source 1',
|
|
147
|
+
filetype: 'pdf',
|
|
148
|
+
fields: {},
|
|
149
|
+
primaryId: 'primary-id-1',
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const citationStream: AgentCitationType = {
|
|
153
|
+
type: 'CUSTOM',
|
|
154
|
+
timestamp: new Date().valueOf(),
|
|
155
|
+
name: 'citations',
|
|
156
|
+
value: {
|
|
157
|
+
citations: [exampleCitation],
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const runFinishedStream = (answerId: string): AgentRunType => ({
|
|
162
|
+
type: 'RUN_FINISHED',
|
|
163
|
+
timestamp: new Date().valueOf(),
|
|
164
|
+
threadId: STREAM_ID,
|
|
165
|
+
runId: answerId,
|
|
166
|
+
result: {
|
|
167
|
+
completionReason: 'ANSWERED',
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
export type AgentMessage =
|
|
172
|
+
| AgentRunType
|
|
173
|
+
| AgentCustomType
|
|
174
|
+
| AgentStepType
|
|
175
|
+
| AgentToolCallType
|
|
176
|
+
| AgentToolCallArgsType
|
|
177
|
+
| AgentTextMessageType
|
|
178
|
+
| AgentCitationType;
|
|
179
|
+
|
|
180
|
+
export type AgentData = {
|
|
181
|
+
answerStreams: Array<AgentMessage>;
|
|
182
|
+
followUpStreams: Array<Array<AgentMessage>>;
|
|
183
|
+
conversationId: string;
|
|
184
|
+
answerId1: string;
|
|
185
|
+
answerId2: string;
|
|
186
|
+
answerId3: string;
|
|
187
|
+
conversationToken: string;
|
|
188
|
+
citations: Array<AgentCitation>;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const agentData: AgentData = {
|
|
192
|
+
answerStreams: [
|
|
193
|
+
runStartStream(ANSWER_ID_1),
|
|
194
|
+
customInitialHeadersStream(true),
|
|
195
|
+
stepStartedStream('Searching'),
|
|
196
|
+
toolCallStartStream('search'),
|
|
197
|
+
searchQueryToolCallArgsStream('test'),
|
|
198
|
+
toolCallEndStream('search'),
|
|
199
|
+
stepFinishedStream('Searching'),
|
|
200
|
+
stepStartedStream('Answering'),
|
|
201
|
+
textMessageStream('### Testing in Coveo\n\nclick **Edit components**.\n - On the **A/B test** tab, click **Configure A/B test**.\n - Set the traffic ratio and configure the **Test scenario**.\n - Click **Start** to activate the A/B test.\n\n2. **Edit an A/B Test**\n - Follow the same steps as creating an A/B test.\n - Click **Edit A/B test** and adjust the traffic ratio.'),
|
|
202
|
+
citationStream,
|
|
203
|
+
stepFinishedStream('Answering'),
|
|
204
|
+
runFinishedStream(ANSWER_ID_1),
|
|
205
|
+
],
|
|
206
|
+
followUpStreams: [
|
|
207
|
+
[
|
|
208
|
+
runStartStream(ANSWER_ID_2),
|
|
209
|
+
customInitialHeadersStream(true),
|
|
210
|
+
stepStartedStream('Thinking'),
|
|
211
|
+
stepFinishedStream('Thinking'),
|
|
212
|
+
stepStartedStream('Searching'),
|
|
213
|
+
toolCallStartStream('search'),
|
|
214
|
+
searchQueryToolCallArgsStream('follow-up question'),
|
|
215
|
+
toolCallEndStream('search'),
|
|
216
|
+
stepFinishedStream('Searching'),
|
|
217
|
+
stepStartedStream('Answering'),
|
|
218
|
+
textMessageStream('This is a follow-up answer.'),
|
|
219
|
+
citationStream,
|
|
220
|
+
stepFinishedStream('Answering'),
|
|
221
|
+
runFinishedStream(ANSWER_ID_2),
|
|
222
|
+
],
|
|
223
|
+
[
|
|
224
|
+
runStartStream(ANSWER_ID_3),
|
|
225
|
+
customInitialHeadersStream(true),
|
|
226
|
+
stepStartedStream('Thinking'),
|
|
227
|
+
stepFinishedStream('Thinking'),
|
|
228
|
+
stepStartedStream('Searching'),
|
|
229
|
+
toolCallStartStream('search'),
|
|
230
|
+
searchQueryToolCallArgsStream('third question'),
|
|
231
|
+
toolCallEndStream('search'),
|
|
232
|
+
stepFinishedStream('Searching'),
|
|
233
|
+
stepStartedStream('Answering'),
|
|
234
|
+
textMessageStream('This is the third answer.'),
|
|
235
|
+
citationStream,
|
|
236
|
+
stepFinishedStream('Answering'),
|
|
237
|
+
runFinishedStream(ANSWER_ID_3),
|
|
238
|
+
],
|
|
239
|
+
],
|
|
240
|
+
conversationId: STREAM_ID,
|
|
241
|
+
answerId1: ANSWER_ID_1,
|
|
242
|
+
answerId2: ANSWER_ID_2,
|
|
243
|
+
answerId3: ANSWER_ID_3,
|
|
244
|
+
conversationToken: CONVERSATION_TOKEN,
|
|
245
|
+
citations: [exampleCitation],
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
export default agentData;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {quanticBase} from '../../../../../../playwright/fixtures/baseFixture';
|
|
2
|
+
import {SearchObject} from '../../../../../../playwright/page-object/searchObject';
|
|
3
|
+
import {
|
|
4
|
+
searchRequestRegex,
|
|
5
|
+
agentAnswerRequestRegex,
|
|
6
|
+
agentFollowUpRequestRegex,
|
|
7
|
+
} from '../../../../../../playwright/utils/requests';
|
|
8
|
+
import {GeneratedAnswerObject} from './pageObject';
|
|
9
|
+
import agentData from './agentData';
|
|
10
|
+
import type {AgentData} from './agentData';
|
|
11
|
+
import {AnalyticsModeEnum} from '../../../../../../playwright/utils/analyticsMode';
|
|
12
|
+
|
|
13
|
+
const pageUrl = 's/quantic-generated-answer';
|
|
14
|
+
|
|
15
|
+
interface AgentOptions {
|
|
16
|
+
agentId: string;
|
|
17
|
+
withToggle: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type QuanticGeneratedAnswerAgentE2EFixtures = {
|
|
21
|
+
agentData: AgentData;
|
|
22
|
+
generatedAnswer: GeneratedAnswerObject;
|
|
23
|
+
search: SearchObject;
|
|
24
|
+
options: Partial<AgentOptions>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const exampleQuery = 'test';
|
|
28
|
+
|
|
29
|
+
export const testAgent =
|
|
30
|
+
quanticBase.extend<QuanticGeneratedAnswerAgentE2EFixtures>({
|
|
31
|
+
pageUrl,
|
|
32
|
+
agentData,
|
|
33
|
+
options: {},
|
|
34
|
+
analyticsMode: AnalyticsModeEnum.legacy,
|
|
35
|
+
search: async ({page}, use) => {
|
|
36
|
+
await use(new SearchObject(page, searchRequestRegex));
|
|
37
|
+
},
|
|
38
|
+
generatedAnswer: async (
|
|
39
|
+
{page, options, configuration, search, agentData: data, analytics},
|
|
40
|
+
use
|
|
41
|
+
) => {
|
|
42
|
+
const generatedAnswerObject = new GeneratedAnswerObject(
|
|
43
|
+
page,
|
|
44
|
+
data.answerId1,
|
|
45
|
+
analytics,
|
|
46
|
+
{
|
|
47
|
+
headAnswerRequestRegex: agentAnswerRequestRegex,
|
|
48
|
+
agentFollowUpRequestRegex,
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
await generatedAnswerObject.mockAgentAnswerResponse(
|
|
53
|
+
data.answerStreams
|
|
54
|
+
);
|
|
55
|
+
await generatedAnswerObject.mockAgentFollowUpResponse(
|
|
56
|
+
data.followUpStreams
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
await search.mockSearchWithBaseResponse();
|
|
60
|
+
await page.goto(pageUrl);
|
|
61
|
+
await configuration.configure(options);
|
|
62
|
+
await search.waitForSearchResponse();
|
|
63
|
+
|
|
64
|
+
generatedAnswerObject.streamEndAnalyticRequestPromise =
|
|
65
|
+
generatedAnswerObject.waitForStreamEndAnalytics();
|
|
66
|
+
generatedAnswerObject.generateRequestPromise =
|
|
67
|
+
generatedAnswerObject.waitForHeadAnswerRequest();
|
|
68
|
+
|
|
69
|
+
await search.fillSearchInput(exampleQuery);
|
|
70
|
+
search.performSearch();
|
|
71
|
+
await search.waitForSearchResponse();
|
|
72
|
+
|
|
73
|
+
await use(generatedAnswerObject);
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
export {expect} from '@playwright/test';
|