@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.
Files changed (32) hide show
  1. package/force-app/main/default/labels/CustomLabels.labels-meta.xml +21 -0
  2. package/force-app/main/default/lwc/quanticGeneratedAnswer/__tests__/quanticGeneratedAnswer.test.js +145 -60
  3. package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/agentData.ts +248 -0
  4. package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/fixture-agent.ts +77 -0
  5. package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/fixture.ts +74 -65
  6. package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/pageObject.ts +157 -15
  7. package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/quanticGeneratedAnswer.e2e.ts +1 -5
  8. package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/quanticGeneratedAnswerAgent.e2e.ts +233 -0
  9. package/force-app/main/default/lwc/quanticGeneratedAnswer/quanticGeneratedAnswer.js +12 -108
  10. package/force-app/main/default/lwc/quanticGeneratedAnswer/templates/conversation.html +1 -1
  11. package/force-app/main/default/lwc/quanticGeneratedAnswer/templates/generatedAnswer.html +8 -47
  12. package/force-app/main/default/lwc/quanticGeneratedAnswerContent/__tests__/quanticGeneratedAnswerContent.test.js +27 -0
  13. package/force-app/main/default/lwc/quanticGeneratedAnswerContent/quanticGeneratedAnswerContent.js +8 -1
  14. package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/__tests__/quanticGeneratedAnswerFollowUpInput.test.js +242 -10
  15. package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/quanticGeneratedAnswerFollowUpInput.css +2 -2
  16. package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/quanticGeneratedAnswerFollowUpInput.html +16 -1
  17. package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/quanticGeneratedAnswerFollowUpInput.js +47 -4
  18. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/__tests__/quanticGeneratedAnswerStreamOfThought.test.js +95 -41
  19. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/__tests__/stepsUtils.test.js +118 -0
  20. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/quanticGeneratedAnswerStreamOfThought.js +21 -35
  21. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/stepsUtils.js +66 -0
  22. package/force-app/main/default/staticresources/coveoheadless/case-assist/headless.js +15 -15
  23. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/product-listing/facets/headless-product-listing-facet-options.d.ts +4 -39
  24. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/search/facets/headless-search-facet-options.d.ts +4 -39
  25. package/force-app/main/default/staticresources/coveoheadless/definitions/features/commerce/facets/facet-set/facet-set-selector.d.ts +3 -9
  26. package/force-app/main/default/staticresources/coveoheadless/definitions/features/facets/facet-search-set/category/category-facet-search-state-selector.d.ts +1 -27
  27. package/force-app/main/default/staticresources/coveoheadless/definitions/features/facets/facet-search-set/specific/specific-facet-search-state-selector.d.ts +1 -27
  28. package/force-app/main/default/staticresources/coveoheadless/headless.js +17 -17
  29. package/force-app/main/default/staticresources/coveoheadless/insight/headless.js +16 -16
  30. package/force-app/main/default/staticresources/coveoheadless/recommendation/headless.js +14 -14
  31. package/force-app/main/default/staticresources/dompurify/purify.min.js +2 -2
  32. package/package.json +7 -6
@@ -0,0 +1,118 @@
1
+ import {resolveSteps} from '../stepsUtils.js';
2
+
3
+ describe('#resolveSteps', () => {
4
+ it('should return empty array for empty input', () => {
5
+ expect(resolveSteps([])).toEqual([]);
6
+ });
7
+
8
+ it('should resolve a full sequence correctly', () => {
9
+ expect(
10
+ resolveSteps([
11
+ {name: 'thinking', status: 'completed', startedAt: 0},
12
+ {name: 'searching', status: 'completed', startedAt: 10},
13
+ {name: 'thinking', status: 'completed', startedAt: 20},
14
+ {name: 'answering', status: 'active', startedAt: 30},
15
+ ])
16
+ ).toEqual([
17
+ {name: 'thinking-before-search', status: 'completed'},
18
+ {name: 'searching', status: 'completed'},
19
+ {name: 'thinking-after-search', status: 'completed'},
20
+ {name: 'answering', status: 'active'},
21
+ ]);
22
+ });
23
+
24
+ it('should handle repeated searching steps', () => {
25
+ expect(
26
+ resolveSteps([
27
+ {name: 'thinking', status: 'completed', startedAt: 0},
28
+ {name: 'searching', status: 'completed', startedAt: 10},
29
+ {name: 'thinking', status: 'completed', startedAt: 20},
30
+ {name: 'searching', status: 'completed', startedAt: 30},
31
+ {name: 'thinking', status: 'active', startedAt: 40},
32
+ ])
33
+ ).toEqual([
34
+ {name: 'thinking-before-search', status: 'completed'},
35
+ {name: 'searching', status: 'completed'},
36
+ {name: 'thinking-after-search', status: 'completed'},
37
+ {name: 'searching', status: 'completed'},
38
+ {name: 'thinking-after-search', status: 'active'},
39
+ ]);
40
+ });
41
+
42
+ it('should resolve searching step with toolCall query to searching-with-query', () => {
43
+ expect(
44
+ resolveSteps([
45
+ {
46
+ name: 'searching',
47
+ status: 'active',
48
+ startedAt: 0,
49
+ toolCalls: [
50
+ {
51
+ toolCallName: 'search',
52
+ toolCallId: 'tc-1',
53
+ startedAt: 0,
54
+ status: 'active',
55
+ type: 'search',
56
+ toolCallArgs: {q: 'how to reset password'},
57
+ },
58
+ ],
59
+ },
60
+ ])
61
+ ).toEqual([
62
+ {
63
+ name: 'searching-with-query',
64
+ status: 'active',
65
+ searchQuery: 'how to reset password',
66
+ },
67
+ ]);
68
+ });
69
+
70
+ it('should expand multiple search toolCalls into separate resolved steps', () => {
71
+ expect(
72
+ resolveSteps([
73
+ {
74
+ name: 'searching',
75
+ status: 'completed',
76
+ startedAt: 0,
77
+ toolCalls: [
78
+ {
79
+ toolCallName: 'search',
80
+ toolCallId: 'tc-1',
81
+ startedAt: 0,
82
+ finishedAt: 1,
83
+ status: 'completed',
84
+ type: 'search',
85
+ toolCallArgs: {q: 'What is Quantic'},
86
+ },
87
+ {
88
+ toolCallName: 'search',
89
+ toolCallId: 'tc-2',
90
+ startedAt: 1,
91
+ finishedAt: 2,
92
+ status: 'completed',
93
+ type: 'search',
94
+ toolCallArgs: {q: 'What is Atomic'},
95
+ },
96
+ ],
97
+ },
98
+ ])
99
+ ).toEqual([
100
+ {
101
+ name: 'searching-with-query',
102
+ status: 'completed',
103
+ searchQuery: 'What is Quantic',
104
+ },
105
+ {
106
+ name: 'searching-with-query',
107
+ status: 'completed',
108
+ searchQuery: 'What is Atomic',
109
+ },
110
+ ]);
111
+ });
112
+
113
+ it('should fall back to searching when toolCalls is absent', () => {
114
+ expect(
115
+ resolveSteps([{name: 'searching', status: 'active', startedAt: 0}])
116
+ ).toEqual([{name: 'searching', status: 'active'}]);
117
+ });
118
+ });
@@ -2,25 +2,25 @@ import analyzingQuestion from '@salesforce/label/c.quantic_AgentGenerationStepAn
2
2
  import analyzingQuestionCompleted from '@salesforce/label/c.quantic_AgentGenerationStepAnalyzingQuestionCompleted';
3
3
  import search from '@salesforce/label/c.quantic_AgentGenerationStepSearch';
4
4
  import searchCompleted from '@salesforce/label/c.quantic_AgentGenerationStepSearchCompleted';
5
+ import searchQuery from '@salesforce/label/c.quantic_AgentGenerationStepSearchQuery';
6
+ import searchQueryCompleted from '@salesforce/label/c.quantic_AgentGenerationStepSearchQueryCompleted';
5
7
  import analyzingResults from '@salesforce/label/c.quantic_AgentGenerationStepAnalyzingResults';
6
8
  import analyzingResultsCompleted from '@salesforce/label/c.quantic_AgentGenerationStepAnalyzingResultsCompleted';
7
9
  import answering from '@salesforce/label/c.quantic_AgentGenerationStepAnswering';
8
10
  import answeringCompleted from '@salesforce/label/c.quantic_AgentGenerationStepAnsweringCompleted';
9
11
  import collapseButton from '@salesforce/label/c.quantic_CollapseButton';
10
12
  import loadingLabel from '@salesforce/label/c.quantic_Loading';
13
+ import {I18nUtils} from 'c/quanticUtils';
11
14
  import {LightningElement, api} from 'lwc';
15
+ import {resolveSteps} from './stepsUtils.js';
12
16
  // @ts-ignore
13
17
  import streamOfThoughtTemplate from './templates/streamOfThought.html';
14
18
  // @ts-ignore
15
19
  import collapsedSummaryTemplate from './templates/collapsedSummary.html';
16
20
 
17
21
  /** @typedef {import("coveo").GenerationStep} GenerationStep */
18
- /** @typedef {'thinking-before-search'|'searching'|'thinking-after-search'|'answering'} ResolvedStepName */
19
- /**
20
- * @typedef {Object} ResolvedStep
21
- * @property {ResolvedStepName} name
22
- * @property {'active'|'completed'} status
23
- */
22
+ /** @typedef {import("./stepsUtils.js").ResolvedStepName} ResolvedStepName */
23
+ /** @typedef {import("./stepsUtils.js").ResolvedStep} ResolvedStep */
24
24
 
25
25
  /** @type {Record<string, {active: string, completed: string}>} */
26
26
  const STEP_LABEL_KEYS = {
@@ -32,6 +32,10 @@ const STEP_LABEL_KEYS = {
32
32
  active: search,
33
33
  completed: searchCompleted,
34
34
  },
35
+ 'searching-with-query': {
36
+ active: searchQuery,
37
+ completed: searchQueryCompleted,
38
+ },
35
39
  'thinking-after-search': {
36
40
  active: analyzingResults,
37
41
  completed: analyzingResultsCompleted,
@@ -42,30 +46,6 @@ const STEP_LABEL_KEYS = {
42
46
  },
43
47
  };
44
48
 
45
- /**
46
- * Maps an array of raw generation steps to resolved steps with a normalized type.
47
- * @param {GenerationStep[]} steps
48
- * @returns {ResolvedStep[]}
49
- */
50
- export function resolveSteps(steps) {
51
- let searchWasPerformed = false;
52
- return steps.map((step) => {
53
- /** @type {ResolvedStepName} */
54
- let name;
55
- if (step.name === 'searching') {
56
- searchWasPerformed = true;
57
- name = 'searching';
58
- } else if (step.name === 'answering') {
59
- name = 'answering';
60
- } else {
61
- name = searchWasPerformed
62
- ? 'thinking-after-search'
63
- : 'thinking-before-search';
64
- }
65
- return {name, status: step.status};
66
- });
67
- }
68
-
69
49
  /**
70
50
  * The `QuanticGeneratedAnswerStreamOfThought` component displays a timeline of agent reasoning
71
51
  * steps during answer generation, showing real-time progress and completion status.
@@ -111,15 +91,19 @@ export default class QuanticGeneratedAnswerStreamOfThought extends LightningElem
111
91
  this._expanded = !this._expanded;
112
92
  };
113
93
 
114
- /** @returns {Array<{key: number, isActive: boolean, label: string}>} */
94
+ /** @returns {Array<{key: number, name: ResolvedStepName, isActive: boolean, label: string}>} */
115
95
  get stepsToDisplay() {
116
96
  return this.steps.map((step, index) => {
117
- const labelKey = STEP_LABEL_KEYS[step.name][step.status];
97
+ const rawLabel = STEP_LABEL_KEYS[step.name][step.status];
98
+ const label =
99
+ step.name === 'searching-with-query'
100
+ ? I18nUtils.format(rawLabel, step.searchQuery)
101
+ : rawLabel;
118
102
  return {
119
103
  key: index,
120
104
  name: step.name,
121
105
  isActive: step.status === 'active',
122
- label: labelKey,
106
+ label,
123
107
  };
124
108
  });
125
109
  }
@@ -152,8 +136,10 @@ export default class QuanticGeneratedAnswerStreamOfThought extends LightningElem
152
136
  /** @returns {string} */
153
137
  get collapsedSummaryLabel() {
154
138
  const lastStep = this.steps[this.steps.length - 1];
155
- const labelKey = STEP_LABEL_KEYS[lastStep.name].completed;
156
- return labelKey;
139
+ const rawLabel = STEP_LABEL_KEYS[lastStep.name].completed;
140
+ return lastStep.name === 'searching-with-query'
141
+ ? I18nUtils.format(rawLabel, lastStep.searchQuery)
142
+ : rawLabel;
157
143
  }
158
144
 
159
145
  render() {
@@ -0,0 +1,66 @@
1
+ /** @typedef {import("coveo").GenerationStep} GenerationStep */
2
+ /** @typedef {'thinking-before-search'|'searching'|'searching-with-query'|'thinking-after-search'|'answering'} ResolvedStepName */
3
+ /**
4
+ * @typedef {Object} ResolvedStep
5
+ * @property {ResolvedStepName} name
6
+ * @property {'active'|'completed'} status
7
+ * @property {string} [searchQuery]
8
+ */
9
+
10
+ /**
11
+ * Maps an array of raw generation steps to resolved steps with a normalized type.
12
+ * @param {GenerationStep[]} steps
13
+ * @returns {ResolvedStep[]}
14
+ */
15
+ export function resolveSteps(steps) {
16
+ let searchWasPerformed = false;
17
+ return steps.flatMap(
18
+ /** @returns {ResolvedStep | ResolvedStep[]} */ (step) => {
19
+ if (step.name === 'searching') {
20
+ searchWasPerformed = true;
21
+ return resolveSearchingStep(step);
22
+ }
23
+ if (step.name === 'answering') {
24
+ return {name: 'answering', status: step.status};
25
+ }
26
+ return {
27
+ name: searchWasPerformed
28
+ ? 'thinking-after-search'
29
+ : 'thinking-before-search',
30
+ status: step.status,
31
+ };
32
+ }
33
+ );
34
+ }
35
+
36
+ /**
37
+ * Resolves a searching step, expanding individual tool calls when present.
38
+ * @param {GenerationStep} step
39
+ * @returns {ResolvedStep[]}
40
+ */
41
+ function resolveSearchingStep(step) {
42
+ const searchToolCalls = step.toolCalls?.filter((tc) => tc.type === 'search');
43
+ if (searchToolCalls?.length) {
44
+ return searchToolCalls.map(resolveSearchToolCall);
45
+ }
46
+ return [{name: 'searching', status: step.status}];
47
+ }
48
+
49
+ /**
50
+ * Resolves a single search tool call into a ResolvedStep.
51
+ * @param {import("coveo").GenerationToolCall} toolCall
52
+ * @returns {ResolvedStep}
53
+ */
54
+ function resolveSearchToolCall(toolCall) {
55
+ const query =
56
+ toolCall.toolCallArgs && 'q' in toolCall.toolCallArgs
57
+ ? toolCall.toolCallArgs.q
58
+ : undefined;
59
+ return query
60
+ ? {
61
+ name: 'searching-with-query',
62
+ status: toolCall.status,
63
+ searchQuery: query,
64
+ }
65
+ : {name: 'searching', status: toolCall.status};
66
+ }