@coveo/quantic 3.43.3 → 3.43.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/force-app/main/default/lwc/quanticBreadcrumbManager/e2e/data.ts +130 -0
  2. package/force-app/main/default/lwc/quanticBreadcrumbManager/e2e/fixture.ts +25 -14
  3. package/force-app/main/default/lwc/quanticBreadcrumbManager/e2e/quanticBreadcrumbManager.e2e.ts +57 -16
  4. package/force-app/main/default/lwc/quanticCardContainer/quanticCardContainer.css +3 -4
  5. package/force-app/main/default/lwc/quanticCardContainer/quanticCardContainer.html +1 -1
  6. package/force-app/main/default/lwc/quanticCarousel/quanticCarousel.css +5 -5
  7. package/force-app/main/default/lwc/quanticCaseClassification/quanticCaseClassification.css +3 -3
  8. package/force-app/main/default/lwc/quanticCategoryFacet/quanticCategoryFacet.css +1 -1
  9. package/force-app/main/default/lwc/quanticCitation/quanticCitation.css +12 -11
  10. package/force-app/main/default/lwc/quanticDidYouMean/e2e/fixture.ts +6 -2
  11. package/force-app/main/default/lwc/quanticDocumentSuggestion/quanticDocumentSuggestion.css +2 -2
  12. package/force-app/main/default/lwc/quanticFacet/quanticFacet.css +1 -1
  13. package/force-app/main/default/lwc/quanticFacetManager/e2e/data.ts +59 -0
  14. package/force-app/main/default/lwc/quanticFacetManager/e2e/fixture.ts +26 -15
  15. package/force-app/main/default/lwc/quanticFacetManager/e2e/quanticFacetManager.e2e.ts +7 -7
  16. package/force-app/main/default/lwc/quanticFacetStyles/quanticFacetStyles.css +10 -10
  17. package/force-app/main/default/lwc/quanticFeedbackModalQna/templates/quanticFeedbackModalQna.css +1 -1
  18. package/force-app/main/default/lwc/quanticFoldedResultList/e2e/fixture.ts +6 -2
  19. package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/agentData.ts +32 -1
  20. package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/pageObject.ts +6 -0
  21. package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/quanticGeneratedAnswerAgent.e2e.ts +66 -1
  22. package/force-app/main/default/lwc/quanticGeneratedAnswer/quanticGeneratedAnswer.css +1 -1
  23. package/force-app/main/default/lwc/quanticGeneratedAnswer/templates/generatedAnswer.css +3 -3
  24. package/force-app/main/default/lwc/quanticGeneratedAnswerBody/__tests__/quanticGeneratedAnswerBody.test.js +39 -0
  25. package/force-app/main/default/lwc/quanticGeneratedAnswerBody/quanticGeneratedAnswerBody.js +4 -1
  26. package/force-app/main/default/lwc/quanticGeneratedAnswerContent/templates/generatedMarkdownContent.css +21 -21
  27. package/force-app/main/default/lwc/quanticGeneratedAnswerContent/templates/generatedTextContent.css +2 -2
  28. package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/quanticGeneratedAnswerFollowUpInput.css +9 -9
  29. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/quanticGeneratedAnswerStreamOfThought.css +2 -2
  30. package/force-app/main/default/lwc/quanticGeneratedAnswerThread/quanticGeneratedAnswerThread.css +8 -8
  31. package/force-app/main/default/lwc/quanticInsightSummary/quanticInsightSummary.css +2 -1
  32. package/force-app/main/default/lwc/quanticModal/quanticModal.css +3 -3
  33. package/force-app/main/default/lwc/quanticNotifications/e2e/fixture.ts +6 -2
  34. package/force-app/main/default/lwc/quanticNotifications/quanticNotifications.css +2 -2
  35. package/force-app/main/default/lwc/quanticPill/quanticPill.css +2 -2
  36. package/force-app/main/default/lwc/quanticPlaceholder/quanticPlaceholder.css +2 -6
  37. package/force-app/main/default/lwc/quanticPlaceholder/quanticPlaceholder.html +1 -1
  38. package/force-app/main/default/lwc/quanticRadioButtonsGroup/quanticRadioButtonsGroup.css +9 -9
  39. package/force-app/main/default/lwc/quanticRecentQueriesList/e2e/fixture.ts +1 -0
  40. package/force-app/main/default/lwc/quanticRecentQueriesList/quanticRecentQueriesList.css +3 -7
  41. package/force-app/main/default/lwc/quanticRecentQueriesList/quanticRecentQueriesList.html +1 -1
  42. package/force-app/main/default/lwc/quanticRecentResultsList/e2e/fixture.ts +1 -0
  43. package/force-app/main/default/lwc/quanticRecentResultsList/quanticRecentResultsList.css +2 -6
  44. package/force-app/main/default/lwc/quanticRecentResultsList/quanticRecentResultsList.html +1 -1
  45. package/force-app/main/default/lwc/quanticRecommendationList/e2e/fixture.ts +1 -0
  46. package/force-app/main/default/lwc/quanticRecommendationList/quanticRecommendationList.css +1 -1
  47. package/force-app/main/default/lwc/quanticRefineToggle/quanticRefineToggle.css +4 -4
  48. package/force-app/main/default/lwc/quanticResultActionStyles/quanticResultActionStyles.css +2 -2
  49. package/force-app/main/default/lwc/quanticResultCopyToClipboard/e2e/fixture.ts +5 -2
  50. package/force-app/main/default/lwc/quanticResultLink/quanticResultLink.css +1 -1
  51. package/force-app/main/default/lwc/quanticResultList/e2e/fixture.ts +6 -2
  52. package/force-app/main/default/lwc/quanticResultPrintableUri/quanticResultPrintableUri.css +1 -1
  53. package/force-app/main/default/lwc/quanticResultQuickview/e2e/fixture.ts +7 -3
  54. package/force-app/main/default/lwc/quanticResultQuickview/quanticResultQuickview.css +6 -6
  55. package/force-app/main/default/lwc/quanticResultTag/quanticResultTag.css +2 -0
  56. package/force-app/main/default/lwc/quanticResultTemplate/quanticResultTemplate.css +1 -1
  57. package/force-app/main/default/lwc/quanticResultsPerPage/e2e/fixture.ts +6 -2
  58. package/force-app/main/default/lwc/quanticSearchBox/e2e/fixture.ts +3 -1
  59. package/force-app/main/default/lwc/quanticSearchBoxInput/templates/defaultSearchBoxInput.css +1 -1
  60. package/force-app/main/default/lwc/quanticSearchBoxInput/templates/expandableSearchBoxInput.css +4 -12
  61. package/force-app/main/default/lwc/quanticSearchBoxInput/templates/expandableSearchBoxInput.html +2 -2
  62. package/force-app/main/default/lwc/quanticSearchBoxSuggestionsList/e2e/fixture.ts +3 -0
  63. package/force-app/main/default/lwc/quanticSmartSnippet/e2e/fixture.ts +6 -4
  64. package/force-app/main/default/lwc/quanticSmartSnippetSource/quanticSmartSnippetSource.css +1 -1
  65. package/force-app/main/default/lwc/quanticSmartSnippetSuggestions/e2e/fixture.ts +6 -4
  66. package/force-app/main/default/lwc/quanticSort/quanticSort.css +3 -3
  67. package/force-app/main/default/lwc/quanticSourceCitations/quanticSourceCitations.css +1 -1
  68. package/force-app/main/default/lwc/quanticStandaloneSearchBox/e2e/fixture.ts +2 -1
  69. package/force-app/main/default/lwc/quanticStatefulButton/quanticStatefulButton.css +2 -2
  70. package/force-app/main/default/lwc/quanticTab/e2e/fixture.ts +6 -2
  71. package/force-app/main/default/lwc/quanticTabBar/e2e/fixture.ts +6 -2
  72. package/force-app/main/default/lwc/quanticTabBar/e2e/quanticTabBar.e2e.ts +3 -2
  73. package/force-app/main/default/lwc/quanticThreadItem/quanticThreadItem.css +6 -6
  74. package/force-app/main/default/lwc/quanticThreadItem/quanticThreadItem.js +0 -1
  75. package/force-app/main/default/lwc/quanticTimeframeFacet/quanticTimeframeFacet.css +1 -1
  76. package/force-app/main/default/lwc/quanticTooltip/quanticTooltip.css +3 -3
  77. package/force-app/main/default/lwc/quanticUserAction/quanticUserAction.css +7 -7
  78. package/force-app/main/default/lwc/quanticUserActionsSession/quanticUserActionsSession.css +3 -3
  79. package/force-app/main/default/lwc/quanticUserActionsTimeline/templates/userActionsTimeline.css +2 -2
  80. package/force-app/main/default/lwc/searchBoxStyle/searchBoxStyle.css +10 -10
  81. package/force-app/main/default/staticresources/coveoheadless/case-assist/headless.js +17 -17
  82. package/force-app/main/default/staticresources/coveoheadless/definitions/api/analytics/case-assist-analytics.d.ts +2 -1
  83. package/force-app/main/default/staticresources/coveoheadless/definitions/api/analytics/insight-analytics.d.ts +2 -1
  84. package/force-app/main/default/staticresources/coveoheadless/definitions/api/analytics/search-analytics.d.ts +2 -1
  85. package/force-app/main/default/staticresources/coveoheadless/definitions/api/knowledge/stream-answer-api.d.ts +2 -1
  86. package/force-app/main/default/staticresources/coveoheadless/definitions/app/engine-configuration.d.ts +34 -0
  87. package/force-app/main/default/staticresources/coveoheadless/definitions/app/insight-thunk-extra-arguments.d.ts +2 -0
  88. package/force-app/main/default/staticresources/coveoheadless/definitions/app/search-thunk-extra-arguments.d.ts +2 -0
  89. package/force-app/main/default/staticresources/coveoheadless/definitions/app/thunk-extra-arguments.d.ts +9 -0
  90. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/core/generated-answer/headless-core-generated-answer.d.ts +1 -25
  91. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/core/generated-answer/headless-searchapi-generated-answer.d.ts +2 -1
  92. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/field-suggestions/facet/headless-field-suggestions.d.ts +1 -0
  93. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/knowledge/generated-answer/headless-answerapi-generated-answer.d.ts +2 -1
  94. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/knowledge/generated-answer/headless-generated-answer-with-follow-ups.d.ts +2 -1
  95. package/force-app/main/default/staticresources/coveoheadless/definitions/features/analytics/analytics-utils.d.ts +1 -0
  96. package/force-app/main/default/staticresources/coveoheadless/definitions/features/attached-results/attached-results-analytics-actions.d.ts +4 -0
  97. package/force-app/main/default/staticresources/coveoheadless/definitions/features/generated-answer/generated-answer-analytics-client.d.ts +38 -0
  98. package/force-app/main/default/staticresources/coveoheadless/definitions/features/generated-answer/generated-answer-insight-analytics-actions.d.ts +2 -2
  99. package/force-app/main/default/staticresources/coveoheadless/definitions/features/result/result-insight-analytics-actions.d.ts +1 -0
  100. package/force-app/main/default/staticresources/coveoheadless/headless.js +17 -17
  101. package/force-app/main/default/staticresources/coveoheadless/insight/headless.js +16 -16
  102. package/force-app/main/default/staticresources/coveoheadless/recommendation/headless.js +16 -16
  103. package/package.json +3 -3
@@ -1,12 +1,13 @@
1
1
  import {FacetManagerObject} from './pageObject';
2
- import {quanticBase} from '../../../../../../playwright/fixtures/baseFixture';
2
+ import {facetBase} from '../../../../../../playwright/fixtures/baseFacetFixture';
3
3
  import {
4
4
  searchRequestRegex,
5
5
  insightSearchRequestRegex,
6
6
  } from '../../../../../../playwright/utils/requests';
7
7
  import {InsightSetupObject} from '../../../../../../playwright/page-object/insightSetupObject';
8
8
  import {useCaseEnum} from '../../../../../../playwright/utils/useCase';
9
- import {SearchObject} from '../../../../../../playwright/page-object/searchObject';
9
+ import {BaseFacetObject} from '../../../../../../playwright/page-object/baseFacetObject';
10
+ import facetManagerData from './data';
10
11
 
11
12
  const pageUrl = 's/quantic-facet-manager';
12
13
 
@@ -14,7 +15,6 @@ interface FacetManagerOptions {}
14
15
 
15
16
  type QuanticFacetManagerE2ESearchFixtures = {
16
17
  facetManager: FacetManagerObject;
17
- search: SearchObject;
18
18
  options: Partial<FacetManagerOptions>;
19
19
  };
20
20
 
@@ -24,41 +24,52 @@ type QuanticFacetManagerE2EInsightFixtures =
24
24
  };
25
25
 
26
26
  export const testSearch =
27
- quanticBase.extend<QuanticFacetManagerE2ESearchFixtures>({
27
+ facetBase.extend<QuanticFacetManagerE2ESearchFixtures>({
28
28
  options: {},
29
- search: async ({page}, use) => {
30
- await use(new SearchObject(page, searchRequestRegex));
29
+ facetResponses: {responses: [facetManagerData]},
30
+ baseFacet: async ({page}, use) => {
31
+ await use(new BaseFacetObject(page, searchRequestRegex));
31
32
  },
32
- facetManager: async ({page, options, configuration, search}, use) => {
33
+ facetManager: async (
34
+ {page, options, configuration, baseFacet, facetResponses},
35
+ use
36
+ ) => {
37
+ await baseFacet.mockSearchWithFacetResponseSequence(
38
+ facetResponses?.responses
39
+ );
33
40
  await page.goto(pageUrl);
34
41
  configuration.configure(options);
35
- await search.waitForSearchResponse();
42
+ await baseFacet.waitForSearchResponse();
36
43
 
37
44
  await use(new FacetManagerObject(page));
38
45
  },
39
46
  });
40
47
 
41
48
  export const testInsight =
42
- quanticBase.extend<QuanticFacetManagerE2EInsightFixtures>({
49
+ facetBase.extend<QuanticFacetManagerE2EInsightFixtures>({
43
50
  options: {},
44
- search: async ({page}, use) => {
45
- await use(new SearchObject(page, insightSearchRequestRegex));
51
+ facetResponses: {responses: [facetManagerData]},
52
+ baseFacet: async ({page}, use) => {
53
+ await use(new BaseFacetObject(page, insightSearchRequestRegex));
46
54
  },
47
55
  insightSetup: async ({page}, use) => {
48
56
  await use(new InsightSetupObject(page));
49
57
  },
50
58
  facetManager: async (
51
- {page, options, search, configuration, insightSetup},
59
+ {page, options, baseFacet, configuration, insightSetup, facetResponses},
52
60
  use
53
61
  ) => {
62
+ await baseFacet.mockSearchWithFacetResponseSequence(
63
+ facetResponses?.responses
64
+ );
54
65
  await page.goto(pageUrl);
55
66
  configuration.configure({...options, useCase: useCaseEnum.insight});
56
67
  await insightSetup.waitForInsightInterfaceInitialization();
57
- const searchResponsePromise = search.waitForSearchResponse();
58
- await search.performSearch();
68
+ const searchResponsePromise = baseFacet.waitForSearchResponse();
69
+ await baseFacet.performSearch();
59
70
  await searchResponsePromise;
60
71
  await use(new FacetManagerObject(page));
61
72
  },
62
73
  });
63
74
 
64
- export {expect} from '@playwright/test';
75
+ export {expect} from '@playwright/test';
@@ -23,10 +23,10 @@ useCaseTestCases.forEach((useCase) => {
23
23
  test.describe(`quantic facet manager ${useCase.label}`, () => {
24
24
  test('should load facets in the same order as in the initial search response', async ({
25
25
  facetManager,
26
- search,
26
+ baseFacet,
27
27
  }) => {
28
- const searchResponsePromise = search.waitForSearchResponse();
29
- await search.performSearch();
28
+ const searchResponsePromise = baseFacet.waitForSearchResponse();
29
+ await baseFacet.performSearch();
30
30
 
31
31
  const searchResponse = await searchResponsePromise;
32
32
  const {facets} = await searchResponse.json();
@@ -45,11 +45,11 @@ useCaseTestCases.forEach((useCase) => {
45
45
  test.describe('when the facets are reordered', () => {
46
46
  test('should load facets in the reordered order', async ({
47
47
  facetManager,
48
- search,
48
+ baseFacet,
49
49
  }) => {
50
- await search.mockSearchFacetOrder(exampleFacetsOrder);
51
- const searchResponsePromise = search.waitForSearchResponse();
52
- await search.performSearch();
50
+ await baseFacet.mockSearchFacetOrder(exampleFacetsOrder);
51
+ const searchResponsePromise = baseFacet.waitForSearchResponse();
52
+ await baseFacet.performSearch();
53
53
 
54
54
  const searchResponse = await searchResponsePromise;
55
55
  const {facets} = await searchResponse.json();
@@ -1,8 +1,8 @@
1
1
  .facet__search-results_no-match {
2
- color: var(--lwc-colorTextLabel, #696969);
2
+ color: var(--slds-g-color-on-surface-1, var(--lwc-colorTextLabel, #696969));
3
3
  background-color: var(--slds-g-color-surface-2, #F6F7F9);
4
4
  font-size: var(--slds-g-font-scale-neg-1, 12px);
5
- border-radius: 4px;
5
+ border-radius: var(--slds-g-radius-border-2, 4px);
6
6
  }
7
7
 
8
8
  fieldset {
@@ -11,16 +11,16 @@ fieldset {
11
11
 
12
12
  .facet__show-less {
13
13
  font-size: var(--slds-g-font-scale-neg-1, 12px);
14
- background-color: white;
15
- color: var(--lwc-colorTextPlaceholder, var(--lwc-colorTextIconDefault, #747474));
14
+ background-color: var(--slds-g-color-surface-1, white);
15
+ color: var(--slds-g-color-on-surface-1, var(--lwc-colorTextPlaceholder, var(--lwc-colorTextIconDefault, #747474)));
16
16
  border: none;
17
17
  margin-bottom: 5px;
18
18
  }
19
19
 
20
20
  .facet__show-more {
21
21
  font-size: var(--slds-g-font-scale-neg-1, 12px);
22
- background-color: white;
23
- color: var(--lwc-brandTextLink, dodgerblue);
22
+ background-color: var(--slds-g-color-surface-1, white);
23
+ color: var(--slds-s-link-color, var(--lwc-brandTextLink, dodgerblue));
24
24
  border: none;
25
25
  }
26
26
 
@@ -39,12 +39,12 @@ fieldset {
39
39
  display: flex;
40
40
  flex-direction: row;
41
41
  cursor: pointer;
42
- border-radius: .25rem;
42
+ border-radius: var(--slds-g-radius-border-2, .25rem);
43
43
  }
44
44
 
45
45
  .facet__value-option:hover {
46
- color: var(--lwc-brandTextLink, dodgerblue);
47
- background-color: #f6f7f9;
46
+ color: var(--slds-s-link-color, var(--lwc-brandTextLink, dodgerblue));
47
+ background-color: var(--slds-g-color-surface-2, #f6f7f9);
48
48
  }
49
49
 
50
50
  .facet__clear-filter {
@@ -52,5 +52,5 @@ fieldset {
52
52
  }
53
53
 
54
54
  .facet__number-of-results {
55
- color: var(--lwc-colorTextPlaceholder, var(--lwc-colorTextIconDefault, #747474));
55
+ color: var(--slds-g-color-on-surface-1, var(--lwc-colorTextPlaceholder, var(--lwc-colorTextIconDefault, #747474)));
56
56
  }
@@ -15,6 +15,6 @@
15
15
  flex-direction: column;
16
16
  }
17
17
  .feedback-modal-qna__radio-group {
18
- margin-top: 0.5rem;
18
+ margin-top: var(--slds-g-spacing-2, 0.5rem);
19
19
  }
20
20
  }
@@ -36,6 +36,7 @@ export const testSearch =
36
36
  await use(new SearchObject(page, searchRequestRegex));
37
37
  },
38
38
  resultList: async ({page, options, configuration, search}, use) => {
39
+ await search.mockSearchWithBaseResponse();
39
40
  await page.goto(pageUrl);
40
41
  configuration.configure(options);
41
42
  await search.waitForSearchResponse();
@@ -57,11 +58,14 @@ export const testInsight =
57
58
  {page, options, search, configuration, insightSetup},
58
59
  use
59
60
  ) => {
61
+ await search.mockSearchWithBaseResponse();
60
62
  await page.goto(pageUrl);
61
63
  configuration.configure({...options, useCase: useCaseEnum.insight});
62
64
  await insightSetup.waitForInsightInterfaceInitialization();
63
- await search.performSearch();
64
- await search.waitForSearchResponse();
65
+ await Promise.all([
66
+ search.waitForSearchResponse(),
67
+ search.performSearch(),
68
+ ]);
65
69
  await search.waitForSearchResultsVisible();
66
70
  await use(new FoldedResultListObject(page));
67
71
  },
@@ -66,6 +66,13 @@ type AgentCitationType = {
66
66
  };
67
67
  };
68
68
 
69
+ type AgentRunErrorType = {
70
+ type: 'RUN_ERROR';
71
+ timestamp: number;
72
+ message: string;
73
+ code: string;
74
+ };
75
+
69
76
  const STREAM_ID = 'conv_1';
70
77
  const ANSWER_ID_1 = 'conv_1_0001';
71
78
  const ANSWER_ID_2 = 'conv_1_0002';
@@ -168,6 +175,16 @@ const runFinishedStream = (answerId: string): AgentRunType => ({
168
175
  },
169
176
  });
170
177
 
178
+ const runErrorStream = (
179
+ message: string,
180
+ code: string
181
+ ): AgentRunErrorType => ({
182
+ type: 'RUN_ERROR',
183
+ timestamp: new Date().valueOf(),
184
+ message,
185
+ code,
186
+ });
187
+
171
188
  export type AgentMessage =
172
189
  | AgentRunType
173
190
  | AgentCustomType
@@ -175,7 +192,21 @@ export type AgentMessage =
175
192
  | AgentToolCallType
176
193
  | AgentToolCallArgsType
177
194
  | AgentTextMessageType
178
- | AgentCitationType;
195
+ | AgentCitationType
196
+ | AgentRunErrorType;
197
+
198
+ export const turnLimitErrorStream: Array<AgentMessage> = [
199
+ runStartStream(ANSWER_ID_2),
200
+ runErrorStream(
201
+ 'The conversation turn limit has been reached.',
202
+ 'KNOWLEDGE:SSE_TURN_LIMIT_REACHED'
203
+ ),
204
+ ];
205
+
206
+ export const genericErrorStream: Array<AgentMessage> = [
207
+ runStartStream(ANSWER_ID_2),
208
+ runErrorStream('An unexpected error occurred.', 'KNOWLEDGE:SSE_INTERNAL_ERROR'),
209
+ ];
179
210
 
180
211
  export type AgentData = {
181
212
  answerStreams: Array<AgentMessage>;
@@ -549,6 +549,12 @@ export class GeneratedAnswerObject {
549
549
  });
550
550
  }
551
551
 
552
+ async mockAgentFollowUpNetworkError() {
553
+ await this.page.route('**/agents/*/follow-up', (route) => {
554
+ route.abort('connectionrefused');
555
+ });
556
+ }
557
+
552
558
  get followUpInput(): Locator {
553
559
  return this.page.locator(
554
560
  'c-quantic-generated-answer-follow-up-input textarea'
@@ -1,5 +1,5 @@
1
1
  import {testAgent, expect} from './fixture-agent';
2
- import agentData from './agentData';
2
+ import agentData, {turnLimitErrorStream, genericErrorStream} from './agentData';
3
3
  import {
4
4
  analyticsModeTest,
5
5
  AnalyticsModeEnum,
@@ -231,3 +231,68 @@ analyticsModeTest.forEach((analytics) => {
231
231
  );
232
232
  });
233
233
  });
234
+
235
+ testAgent.describe('quantic generated answer - agent follow-up error handling', () => {
236
+ testAgent.use({
237
+ options: {agentId: exampleAgentId},
238
+ });
239
+
240
+ testAgent(
241
+ 'should display a generic error message when the follow-up request fails due to a network error',
242
+ async ({generatedAnswer}) => {
243
+ await generatedAnswer.streamEndAnalyticRequestPromise;
244
+ await generatedAnswer.mockAgentFollowUpNetworkError();
245
+
246
+ await generatedAnswer.typeFollowUpQuestion('follow-up question');
247
+ await generatedAnswer.submitFollowUp();
248
+
249
+ await expect(generatedAnswer.threadItems).toHaveCount(2);
250
+
251
+ const errorMessage = generatedAnswer.threadItems
252
+ .last()
253
+ .getByTestId('generated-answer-body__error');
254
+ await expect(errorMessage).toBeVisible();
255
+ await expect(errorMessage).toContainText('Something went wrong.');
256
+ }
257
+ );
258
+
259
+ testAgent(
260
+ 'should display a distinct turn-limit message when the follow-up SSE stream reports a turn-limit error',
261
+ async ({generatedAnswer}) => {
262
+ await generatedAnswer.streamEndAnalyticRequestPromise;
263
+ await generatedAnswer.mockAgentFollowUpResponse([turnLimitErrorStream]);
264
+
265
+ await generatedAnswer.typeFollowUpQuestion('follow-up question');
266
+ await generatedAnswer.submitFollowUp();
267
+
268
+ await expect(generatedAnswer.threadItems).toHaveCount(2);
269
+
270
+ const errorMessage = generatedAnswer.threadItems
271
+ .last()
272
+ .getByTestId('generated-answer-body__error');
273
+ await expect(errorMessage).toBeVisible();
274
+ await expect(errorMessage).toContainText(
275
+ 'Conversation turn limit reached. Please start a new conversation.'
276
+ );
277
+ }
278
+ );
279
+
280
+ testAgent(
281
+ 'should display a generic error message when the follow-up SSE stream reports a generic error',
282
+ async ({generatedAnswer}) => {
283
+ await generatedAnswer.streamEndAnalyticRequestPromise;
284
+ await generatedAnswer.mockAgentFollowUpResponse([genericErrorStream]);
285
+
286
+ await generatedAnswer.typeFollowUpQuestion('follow-up question');
287
+ await generatedAnswer.submitFollowUp();
288
+
289
+ await expect(generatedAnswer.threadItems).toHaveCount(2);
290
+
291
+ const errorMessage = generatedAnswer.threadItems
292
+ .last()
293
+ .getByTestId('generated-answer-body__error');
294
+ await expect(errorMessage).toBeVisible();
295
+ await expect(errorMessage).toContainText('Something went wrong.');
296
+ }
297
+ );
298
+ });
@@ -1,3 +1,3 @@
1
1
  .generated-answer__header-title {
2
- color: var(--lwc-brandPrimary, #1b96ff);
2
+ color: var(--slds-g-color-accent-1, var(--lwc-brandPrimary, #1b96ff));
3
3
  }
@@ -10,7 +10,7 @@
10
10
  }
11
11
 
12
12
  .generated-answer__footer {
13
- gap: 1rem;
13
+ gap: var(--slds-g-spacing-4, 1rem);
14
14
  }
15
15
 
16
16
  .generated-answer__answer--collapsed {
@@ -19,12 +19,12 @@
19
19
 
20
20
  .generated-answer__answer--expanded {
21
21
  max-height: 100%;
22
- margin-bottom: 1rem;
22
+ margin-bottom: var(--slds-g-spacing-4, 1rem);
23
23
  overflow: visible;
24
24
  }
25
25
 
26
26
  .generated-answer__collapse-generating-message {
27
- color: var(--lwc-brandPrimary, #1b96ff);
27
+ color: var(--slds-g-color-accent-1, var(--lwc-brandPrimary, #1b96ff));
28
28
  }
29
29
 
30
30
  .generated-answer__answer::after {
@@ -269,6 +269,45 @@ describe('c-quantic-generated-answer-body', () => {
269
269
  expect(error).not.toBeNull();
270
270
  expect(content).toBeNull();
271
271
  });
272
+
273
+ it('should render the generic error message when the error has no code (e.g., a network/transport failure)', async () => {
274
+ const element = createTestComponent({
275
+ ...defaultOptions,
276
+ generatedAnswer: {
277
+ ...defaultOptions.generatedAnswer,
278
+ answer: '',
279
+ // @ts-ignore
280
+ error: {
281
+ message:
282
+ 'An error occurred while starting the follow-up answer generation.',
283
+ },
284
+ },
285
+ });
286
+ await flushPromises();
287
+
288
+ const error = element.shadowRoot.querySelector(selectors.error);
289
+
290
+ expect(error).not.toBeNull();
291
+ expect(error.textContent).toContain(
292
+ 'Something went wrong while generating the answer. Please try again later.'
293
+ );
294
+ });
295
+
296
+ it('should not render the error message when the error object is present but empty', async () => {
297
+ const element = createTestComponent({
298
+ ...defaultOptions,
299
+ generatedAnswer: {
300
+ ...defaultOptions.generatedAnswer,
301
+ // @ts-ignore
302
+ error: {},
303
+ },
304
+ });
305
+ await flushPromises();
306
+
307
+ const error = element.shadowRoot.querySelector(selectors.error);
308
+
309
+ expect(error).toBeNull();
310
+ });
272
311
  });
273
312
 
274
313
  describe('rendering of actions', () => {
@@ -78,7 +78,10 @@ export default class QuanticGeneratedAnswerBody extends LightningElement {
78
78
  }
79
79
 
80
80
  get hasError() {
81
- return !!this.generatedAnswer?.error?.code;
81
+ return (
82
+ !!this.generatedAnswer?.error?.code ||
83
+ !!this.generatedAnswer?.error?.message
84
+ );
82
85
  }
83
86
 
84
87
  get cannotAnswer() {
@@ -13,10 +13,10 @@
13
13
 
14
14
  .generated-answer-content__answer--streaming::after {
15
15
  content: '';
16
- width: 0.5rem;
16
+ width: var(--slds-g-sizing-3, 0.5rem);
17
17
  height: 0.9rem;
18
18
  margin-left: 0.1rem;
19
- background: var(--lwc-brandAccessible, #0176d3);
19
+ background: var(--slds-g-color-accent-container-1, var(--lwc-brandAccessible, #0176d3));
20
20
  display: inline-block;
21
21
  animation: cursor-blink 1.5s steps(2, start) infinite;
22
22
  vertical-align: baseline;
@@ -42,8 +42,8 @@ div[data-level='answer-heading-3'] {
42
42
  }
43
43
 
44
44
  div[data-level] {
45
- margin-top: var(--lwc-spacingMedium, 1rem);
46
- margin-bottom: var(--lwc-spacingXSmall, 0.5rem);
45
+ margin-top: var(--slds-g-spacing-4, var(--lwc-spacingMedium, 1rem));
46
+ margin-bottom: var(--slds-g-spacing-2, var(--lwc-spacingXSmall, 0.5rem));
47
47
  font-weight: var(--slds-g-font-weight-7, bold);
48
48
  }
49
49
 
@@ -57,19 +57,19 @@ td {
57
57
 
58
58
  ol {
59
59
  list-style-type: decimal;
60
- padding-inline-start: var(--lwc-spacingXLarge, 2rem);
61
- margin-bottom: var(--lwc-spacingXSmall, 0.5rem);
60
+ padding-inline-start: var(--slds-g-spacing-6, var(--lwc-spacingXLarge, 2rem));
61
+ margin-bottom: var(--slds-g-spacing-2, var(--lwc-spacingXSmall, 0.5rem));
62
62
  }
63
63
 
64
64
  ul {
65
65
  list-style-type: disc;
66
- padding-inline-start: var(--lwc-spacingXLarge, 2rem);
67
- margin-bottom: var(--lwc-spacingXSmall, 0.5rem);
66
+ padding-inline-start: var(--slds-g-spacing-6, var(--lwc-spacingXLarge, 2rem));
67
+ margin-bottom: var(--slds-g-spacing-2, var(--lwc-spacingXSmall, 0.5rem));
68
68
  }
69
69
 
70
70
  code {
71
71
  padding: var(--lwc-spacingXxxSmall, 0.125rem) var(--lwc-spacingXxSmall, 0.25rem);
72
- border: 1px solid;
72
+ border: var(--slds-g-sizing-border-1, 1px) solid;
73
73
  color: var(--quantic-genqa-inline-code);
74
74
  font-size: var(--quantic-genqa-text-small);
75
75
  background-color: var(--quantic-genqa-bg-neutral-light);
@@ -79,10 +79,10 @@ code {
79
79
  }
80
80
 
81
81
  pre {
82
- padding: var(--lwc-spacingXSmall, 0.5rem);
82
+ padding: var(--slds-g-spacing-2, var(--lwc-spacingXSmall, 0.5rem));
83
83
  overflow: auto;
84
84
  max-height: 24rem;
85
- border: 1px solid;
85
+ border: var(--slds-g-sizing-border-1, 1px) solid;
86
86
  background-color: var(--quantic-genqa-bg-neutral-light);
87
87
  border-color: var(--quantic-genqa-border-neutral);
88
88
  border-radius: var(--quantic-genqa-border-radius);
@@ -97,16 +97,16 @@ pre > code {
97
97
  }
98
98
 
99
99
  blockquote {
100
- margin-left: var(--lwc-spacingXxLarge, 4rem);
101
- margin-right: var(--lwc-spacingXxLarge, 4rem);;
100
+ margin-left: var(--slds-g-spacing-8, var(--lwc-spacingXxLarge, 4rem));
101
+ margin-right: var(--slds-g-spacing-8, var(--lwc-spacingXxLarge, 4rem));;
102
102
  font-size: italic;
103
103
  }
104
104
 
105
105
  .scrollable-table {
106
- margin-top: var(--lwc-spacingLarge, 1.5rem);
107
- margin-bottom: var(--lwc-spacingLarge, 1.5rem);
106
+ margin-top: var(--slds-g-spacing-5, var(--lwc-spacingLarge, 1.5rem));
107
+ margin-bottom: var(--slds-g-spacing-5, var(--lwc-spacingLarge, 1.5rem));
108
108
  display: inline-block;
109
- border: 1px solid;
109
+ border: var(--slds-g-sizing-border-1, 1px) solid;
110
110
  overflow: auto;
111
111
  max-height: 24rem;
112
112
  border-color: var(--quantic-genqa-border-neutral-dim);
@@ -124,11 +124,11 @@ table {
124
124
  }
125
125
 
126
126
  table thead th {
127
- padding: var(--lwc-spacingMedium, 1rem);
127
+ padding: var(--slds-g-spacing-4, var(--lwc-spacingMedium, 1rem));
128
128
  text-align: left;
129
129
  background-color: var(--quantic-genqa-bg-table-header);
130
- border-bottom: solid 2px var(--quantic-genqa-border-neutral-dim);
131
- border-left: solid 1px var(--quantic-genqa-border-neutral-dim);
130
+ border-bottom: solid var(--slds-g-sizing-border-2, 2px) var(--quantic-genqa-border-neutral-dim);
131
+ border-left: solid var(--slds-g-sizing-border-1, 1px) var(--quantic-genqa-border-neutral-dim);
132
132
  }
133
133
 
134
134
  table thead th:first-of-type {
@@ -141,8 +141,8 @@ tbody tr:nth-child(even) {
141
141
 
142
142
  tbody tr td {
143
143
  padding: var(--lwc-spacingMedium, 1rem);
144
- border-left: solid 1px var(--quantic-genqa-border-neutral-dim);
145
- border-bottom: solid 1px var(--quantic-genqa-border-neutral-dim);
144
+ border-left: solid var(--slds-g-sizing-border-1, 1px) var(--quantic-genqa-border-neutral-dim);
145
+ border-bottom: solid var(--slds-g-sizing-border-1, 1px) var(--quantic-genqa-border-neutral-dim);
146
146
  }
147
147
 
148
148
  tbody tr td:first-of-type {
@@ -4,10 +4,10 @@
4
4
 
5
5
  .generated-answer-content__answer--streaming::after {
6
6
  content: '';
7
- width: 0.5rem;
7
+ width: var(--slds-g-sizing-3, 0.5rem);
8
8
  height: 0.9rem;
9
9
  margin-left: 0.1rem;
10
- background: var(--lwc-brandAccessible, #0176d3);
10
+ background: var(--slds-g-color-accent-container-1, var(--lwc-brandAccessible, #0176d3));
11
11
  display: inline-block;
12
12
  animation: cursor-blink 1.5s steps(2, start) infinite;
13
13
  vertical-align: baseline;
@@ -3,13 +3,13 @@
3
3
  }
4
4
 
5
5
  .follow-up-input__container--error {
6
- border-color: var(--lwc-colorBorderError, #ea001e);
6
+ border-color: var(--slds-g-color-error-base-50, var(--lwc-colorBorderError, #ea001e));
7
7
  }
8
8
 
9
9
  .follow-up-input__expander {
10
10
  display: grid;
11
11
  overflow: hidden;
12
- margin-right: 2.5rem;
12
+ margin-right: var(--slds-g-spacing-7, 2.5rem);
13
13
  }
14
14
 
15
15
  .follow-up-input__expander::after {
@@ -26,7 +26,7 @@
26
26
  border: none;
27
27
  outline: none;
28
28
  background: transparent;
29
- padding: 0.5rem 0.75rem;
29
+ padding: var(--slds-g-spacing-2, 0.5rem) var(--slds-g-spacing-3, 0.75rem);
30
30
  font: inherit;
31
31
  min-height: 2.5rem;
32
32
  }
@@ -39,9 +39,9 @@
39
39
  z-index: 10;
40
40
  overflow: visible;
41
41
  margin-right: 0;
42
- background-color: var(--lwc-colorBackground, #fff);
43
- border: 1px solid var(--lwc-brandAccessible, #0176d3);
44
- border-radius: 0.25rem;
42
+ background-color: var(--slds-g-color-surface-1, var(--lwc-colorBackground, #fff));
43
+ border: var(--slds-g-sizing-border-1, 1px) solid var(--slds-g-color-accent-container-1, var(--lwc-brandAccessible, #0176d3));
44
+ border-radius: var(--slds-g-radius-border-2, 0.25rem);
45
45
  }
46
46
 
47
47
  .follow-up-input__expander--expanded::after,
@@ -49,7 +49,7 @@
49
49
  white-space: pre-wrap;
50
50
  overflow-y: auto;
51
51
  max-height: 8rem;
52
- padding-right: 2.5rem;
52
+ padding-right: var(--slds-g-spacing-7, 2.5rem);
53
53
  scrollbar-width: none;
54
54
  }
55
55
 
@@ -59,7 +59,7 @@
59
59
 
60
60
  .follow-up-input__submit-button {
61
61
  position: absolute;
62
- right: 0.25rem;
63
- bottom: 0.25rem;
62
+ right: var(--slds-g-spacing-1, 0.25rem);
63
+ bottom: var(--slds-g-spacing-1, 0.25rem);
64
64
  z-index: 15;
65
65
  }
@@ -6,8 +6,8 @@
6
6
 
7
7
  .stream-of-thought__collapsed-summary:focus-visible,
8
8
  .stream-of-thought__collapse-button:focus-visible {
9
- border-radius: var(--slds-g-sizing-border-4, 0.25rem);
10
- outline: 2px solid var(--lwc-brandPrimary, #1b96ff);
9
+ border-radius: var(--slds-g-radius-border-2, 0.25rem);
10
+ outline: var(--slds-g-sizing-border-2, 2px) solid var(--slds-g-color-accent-1, var(--lwc-brandPrimary, #1b96ff));
11
11
  outline-offset: 2px;
12
12
  }
13
13