Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/free-pots-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@adobe/alloy": patch
---

Added support for configuring Brand Concierge `conversation.voiceEnabled` so the SDK routes requests differently based on the voiceEnabled configuration. Included unit test coverage for config validation and voice subpath routing behavior.
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import { number, objectOf, boolean } from "../../utils/validation/index.js";

export default objectOf({
conversation: objectOf({
voiceEnabled: boolean().default(false),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure you want this on the extension configuration? It seems like it would be better as an option to the sendConversationEvent command.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jonsnyder , our main goal is to use this flag to drive the conversation event routing from client app side. It's supposed to be set:

  • primarily on tenant level
  • optionally on hosting app instance level (i.e. per end user, given that the hosting app surfaces it) before conversation starts

There's no use cases where some events sent with voice enabled and some others sent without it enabled in the same conversation.

So IMO setting it on the extension configuration is the simplest way technical wise. Can you please let me know your thinking behind your suggestion? And also the design philosophy (when to use/not to use it) of extension configurations maybe? Thank you!

CC: @ninaceban

stickyConversationSession: boolean().default(false),
streamTimeout: number()
.integer()
.minimum(STREAM_START_TIMEOUT_MS)
.default(STREAM_START_TIMEOUT_MS),
}).default({
voiceEnabled: false,
stickyConversationSession: false,
streamTimeout: STREAM_START_TIMEOUT_MS,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,22 @@ governing permissions and limitations under the License.
*/
import { createRequest } from "../../utils/request/index.js";

export default ({ payload, action = "conversations", sessionId }) => {
const BRAND_CONCIERGE_PATH = "/brand-concierge";
const VOICE_BRAND_CONCIERGE_PATH = "/brand-concierge-voice";

export default ({
payload,
action = "conversations",
sessionId,
voiceEnabled = false,
}) => {
const edgeSubPath = voiceEnabled
? VOICE_BRAND_CONCIERGE_PATH
: BRAND_CONCIERGE_PATH;

return createRequest({
payload: payload,
edgeSubPath: "/brand-concierge",
edgeSubPath,
requestParams: { sessionId },
getAction() {
return action;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default ({
onBeforeEventSend,
conversation,
} = config;
const { voiceEnabled } = conversation;

return (options) => {
let streamingEnabled = false;
Expand All @@ -46,6 +47,7 @@ export default ({
const request = createConversationServiceRequest({
payload,
sessionId: sessionId,
voiceEnabled,
});

const event = eventManager.createEvent();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,22 @@ describe("createConversationServiceRequest", () => {
});
});

it("uses correct edge subpath", () => {
it("uses default edge subpath when voice is disabled", () => {
const request = createConversationServiceRequest({
payload: mockPayload,
sessionId: mockSessionId,
});

expect(request.getEdgeSubPath()).toBe("/brand-concierge");
});

it("uses voice edge subpath when voice is enabled", () => {
const request = createConversationServiceRequest({
payload: mockPayload,
sessionId: mockSessionId,
voiceEnabled: true,
});

expect(request.getEdgeSubPath()).toBe("/brand-concierge-voice");
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,24 @@ describe("BrandConcierge config validators", () => {
testConfigValidators({
configValidators: createConciergeComponent.configValidators,
validConfigurations: [
{ conversation: { voiceEnabled: true } },
{ conversation: { voiceEnabled: false } },
{ conversation: { stickyConversationSession: true } },
{ conversation: { stickyConversationSession: false } },
{ conversation: { streamTimeout: 10000 } },
{ conversation: { streamTimeout: 20000 } },
{
conversation: { stickyConversationSession: true, streamTimeout: 10000 },
conversation: {
voiceEnabled: true,
stickyConversationSession: true,
streamTimeout: 10000,
},
},
{},
],
invalidConfigurations: [
{ conversation: { voiceEnabled: "true" } },
{ conversation: { voiceEnabled: 123 } },
{ conversation: { stickyConversationSession: "invalid" } },
{ conversation: { stickyConversationSession: 123 } },
{ conversation: { streamTimeout: "invalid" } },
Expand All @@ -159,6 +167,7 @@ describe("BrandConcierge config validators", () => {
});
it("provides default values for concierge configuration", () => {
const config = createConciergeComponent.configValidators({});
expect(config.conversation.voiceEnabled).toBe(false);
expect(config.conversation.stickyConversationSession).toBe(false);
expect(config.conversation.streamTimeout).toBe(10000);
});
Expand Down
Loading