@coveo/quantic 3.42.1 → 3.43.0
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/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 +65 -59
- package/force-app/main/default/lwc/quanticGeneratedAnswer/e2e/pageObject.ts +158 -13
- 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/templates/conversation.html +1 -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 +5 -5
|
@@ -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 {
|
|
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
|
|
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
|
|
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
|
|
156
|
-
return
|
|
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
|
+
}
|