From cbf1bf3cfb5a0a640aa62aaa04e0c8e09d30c306 Mon Sep 17 00:00:00 2001 From: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com> Date: Fri, 17 Apr 2026 19:30:56 +0000 Subject: [PATCH] support-bot: correct messages --- apps/simplex-support-bot/bot.test.ts | 122 +++++++++++------------ apps/simplex-support-bot/src/bot.ts | 4 +- apps/simplex-support-bot/src/cards.ts | 6 +- apps/simplex-support-bot/src/messages.ts | 2 +- 4 files changed, 67 insertions(+), 67 deletions(-) diff --git a/apps/simplex-support-bot/bot.test.ts b/apps/simplex-support-bot/bot.test.ts index ebfa15e91b..46525db78e 100644 --- a/apps/simplex-support-bot/bot.test.ts +++ b/apps/simplex-support-bot/bot.test.ts @@ -422,7 +422,7 @@ async function reachQueue(groupId = CUSTOMER_GROUP_ID) { async function reachGrok(groupId = CUSTOMER_GROUP_ID) { await reachQueue(groupId) // Add the queue message to history so state derivation sees it - addBotMessage("The team can see your message", groupId) + addBotMessage("The team will reply to your message", groupId) // Send /grok command. This triggers activateGrok which needs the join flow. // We need to simulate Grok join success. @@ -460,13 +460,13 @@ async function simulateGrokJoinSuccess(mainGroupId = CUSTOMER_GROUP_ID) { async function reachTeamPending(groupId = CUSTOMER_GROUP_ID) { await reachQueue(groupId) - addBotMessage("The team can see your message", groupId) + addBotMessage("The team will reply to your message", groupId) await bot.onNewChatItems(customerMessage("/team", groupId)) } async function reachTeam(groupId = CUSTOMER_GROUP_ID) { await reachTeamPending(groupId) - addBotMessage("A team member has been added", groupId) + addBotMessage("We will reply within 24 hours.", groupId) chat.members.set(groupId, [makeTeamMember(TEAM_MEMBER_1_ID, "Alice")]) // Team member sends a text message (triggers one-way gate) addTeamMemberMessageToHistory("Hi, how can I help?", TEAM_MEMBER_1_ID, groupId) @@ -574,7 +574,7 @@ describe("Welcome & First Message", () => { test("first message → queue reply sent, card created in team group", async () => { await bot.onNewChatItems(customerMessage("Hello")) - expectSentToGroup(CUSTOMER_GROUP_ID, "The team can see your message") + expectSentToGroup(CUSTOMER_GROUP_ID, "The team will reply to your message") const teamMsgs = chat.sentTo(TEAM_GROUP_ID) expect(teamMsgs.length).toBeGreaterThan(0) expect(teamMsgs[teamMsgs.length - 1]).toContain("/join") @@ -582,22 +582,22 @@ describe("Welcome & First Message", () => { test("non-text first message → no queue reply, no card", async () => { await bot.onNewChatItems(customerNonTextMessage()) - expectNotSentToGroup(CUSTOMER_GROUP_ID, "The team can see your message") + expectNotSentToGroup(CUSTOMER_GROUP_ID, "The team will reply to your message") expect(chat.sentTo(TEAM_GROUP_ID).length).toBe(0) }) test("second message → no duplicate queue reply", async () => { await bot.onNewChatItems(customerMessage("Hello")) - addBotMessage("The team can see your message") - const countBefore = chat.sentTo(CUSTOMER_GROUP_ID).filter(m => m.includes("The team can see your message")).length + addBotMessage("The team will reply to your message") + const countBefore = chat.sentTo(CUSTOMER_GROUP_ID).filter(m => m.includes("The team will reply to your message")).length await bot.onNewChatItems(customerMessage("Second message")) - const countAfter = chat.sentTo(CUSTOMER_GROUP_ID).filter(m => m.includes("The team can see your message")).length + const countAfter = chat.sentTo(CUSTOMER_GROUP_ID).filter(m => m.includes("The team will reply to your message")).length expect(countAfter).toBe(countBefore) }) test("unrecognized /command → treated as normal message", async () => { await bot.onNewChatItems(customerMessage("/unknown")) - expectSentToGroup(CUSTOMER_GROUP_ID, "The team can see your message") + expectSentToGroup(CUSTOMER_GROUP_ID, "The team will reply to your message") }) }) @@ -606,13 +606,13 @@ describe("/grok Activation", () => { test("/grok from QUEUE → Grok invited, grokActivatedMessage sent", async () => { await reachQueue() - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") const joinPromise = simulateGrokJoinSuccess() await bot.onNewChatItems(customerMessage("/grok")) await joinPromise await bot.flush() expectMemberAdded(CUSTOMER_GROUP_ID, GROK_CONTACT_ID) - expectSentToGroup(CUSTOMER_GROUP_ID, "now chatting with Grok") + expectSentToGroup(CUSTOMER_GROUP_ID, "You are chatting with Grok") }) test("/grok as first message → WELCOME→GROK directly, no queue message", async () => { @@ -620,8 +620,8 @@ describe("/grok Activation", () => { await bot.onNewChatItems(customerMessage("/grok")) await joinPromise await bot.flush() - expectSentToGroup(CUSTOMER_GROUP_ID, "now chatting with Grok") - expectNotSentToGroup(CUSTOMER_GROUP_ID, "The team can see your message") + expectSentToGroup(CUSTOMER_GROUP_ID, "You are chatting with Grok") + expectNotSentToGroup(CUSTOMER_GROUP_ID, "The team will reply to your message") expect(chat.sentTo(TEAM_GROUP_ID).length).toBeGreaterThan(0) }) @@ -634,7 +634,7 @@ describe("/grok Activation", () => { test("/grok when grokContactId is null → grokUnavailableMessage", async () => { setup({grokContactId: null}) await reachQueue() - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") await bot.onNewChatItems(customerMessage("/grok")) expectSentToGroup(CUSTOMER_GROUP_ID, "temporarily unavailable") }) @@ -644,7 +644,7 @@ describe("/grok Activation", () => { await bot.onNewChatItems(customerMessage("/grok")) await bot.flush() expectSentToGroup(CUSTOMER_GROUP_ID, "temporarily unavailable") - expectSentToGroup(CUSTOMER_GROUP_ID, "The team can see your message") + expectSentToGroup(CUSTOMER_GROUP_ID, "The team will reply to your message") }) }) @@ -789,22 +789,22 @@ describe("/team Activation", () => { test("/team from QUEUE → ALL team members added, teamAddedMessage sent", async () => { await reachQueue() - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") await bot.onNewChatItems(customerMessage("/team")) expectMemberAdded(CUSTOMER_GROUP_ID, TEAM_MEMBER_1_ID) expectMemberAdded(CUSTOMER_GROUP_ID, TEAM_MEMBER_2_ID) - expectSentToGroup(CUSTOMER_GROUP_ID, "team member has been added") + expectSentToGroup(CUSTOMER_GROUP_ID, "We will reply within") }) test("/team as first message → WELCOME→TEAM, no queue message", async () => { await bot.onNewChatItems(customerMessage("/team")) - expectSentToGroup(CUSTOMER_GROUP_ID, "team member has been added") - expectNotSentToGroup(CUSTOMER_GROUP_ID, "The team can see your message") + expectSentToGroup(CUSTOMER_GROUP_ID, "We will reply within") + expectNotSentToGroup(CUSTOMER_GROUP_ID, "The team will reply to your message") }) test("/team when already activated → teamAlreadyInvitedMessage", async () => { await reachTeamPending() - addBotMessage("A team member has been added") + addBotMessage("We will reply within 24 hours.") chat.members.set(CUSTOMER_GROUP_ID, [makeTeamMember(TEAM_MEMBER_1_ID, "Alice")]) await bot.onNewChatItems(customerMessage("/team")) expectSentToGroup(CUSTOMER_GROUP_ID, "already been invited") @@ -813,7 +813,7 @@ describe("/team Activation", () => { test("/team with no team members → noTeamMembersMessage", async () => { setup({teamMembers: []}) await reachQueue() - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") await bot.onNewChatItems(customerMessage("/team")) expectSentToGroup(CUSTOMER_GROUP_ID, "No team members are available") }) @@ -824,7 +824,7 @@ describe("One-Way Gate", () => { test("team member sends first TEXT → Grok removed if present", async () => { await reachTeamPending() - addBotMessage("A team member has been added") + addBotMessage("We will reply within 24 hours.") chat.members.set(CUSTOMER_GROUP_ID, [makeGrokMember(), makeTeamMember(TEAM_MEMBER_1_ID, "Alice")]) await bot.onNewChatItems(teamMemberMessage("Hi, how can I help?")) expect(chat.removed.some(r => r.groupId === CUSTOMER_GROUP_ID && r.memberIds.includes(7777))).toBe(true) @@ -832,7 +832,7 @@ describe("One-Way Gate", () => { test("team member non-text (no ciContentText) → Grok NOT removed", async () => { await reachTeamPending() - addBotMessage("A team member has been added") + addBotMessage("We will reply within 24 hours.") chat.members.set(CUSTOMER_GROUP_ID, [makeGrokMember()]) await bot.onNewChatItems(teamMemberMessage("", TEAM_MEMBER_1_ID)) expect(chat.removed.length).toBe(0) @@ -854,7 +854,7 @@ describe("One-Way Gate", () => { test("/grok in TEAM-PENDING → invite Grok if not present", async () => { await reachTeamPending() - addBotMessage("A team member has been added") + addBotMessage("We will reply within 24 hours.") chat.members.set(CUSTOMER_GROUP_ID, [makeTeamMember(TEAM_MEMBER_1_ID, "Alice")]) const joinPromise = simulateGrokJoinSuccess() await bot.onNewChatItems(customerMessage("/grok")) @@ -871,8 +871,8 @@ describe("One-Way Gate with Grok Disabled", () => { bot = new SupportBot(chat as any, null, config as any, MAIN_USER_ID, null) bot.cards = cards // Reach QUEUE state with Grok + team member already present - addBotMessage("The team can see your message") - addBotMessage("A team member has been added") + addBotMessage("The team will reply to your message") + addBotMessage("We will reply within 24 hours.") chat.members.set(CUSTOMER_GROUP_ID, [makeGrokMember(), makeTeamMember(TEAM_MEMBER_1_ID, "Alice")]) // Team member sends text → one-way gate should fire await bot.onNewChatItems(teamMemberMessage("Hi, how can I help?")) @@ -885,7 +885,7 @@ describe("One-Way Gate with Grok Disabled", () => { bot.cards = cards // Set up group with Grok member present chat.members.set(CUSTOMER_GROUP_ID, [makeGrokMember()]) - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") // Customer sends text in GROK state await bot.onNewChatItems(customerMessage("How do I use SimpleX?")) // Grok should not respond (grokApi is null) @@ -913,7 +913,7 @@ describe("Team Member Lifecycle", () => { test("all team members leave before sending → reverts to QUEUE", async () => { await reachTeamPending() - addBotMessage("A team member has been added") + addBotMessage("We will reply within 24 hours.") // Remove team members from the group chat.members.set(CUSTOMER_GROUP_ID, []) // Customer sends another message — state should derive as QUEUE (no team members) @@ -923,18 +923,18 @@ describe("Team Member Lifecycle", () => { test("/team after all team members left (TEAM-PENDING, no msg sent) → re-adds members", async () => { await reachTeamPending() - addBotMessage("A team member has been added") + addBotMessage("We will reply within 24 hours.") chat.members.set(CUSTOMER_GROUP_ID, []) chat.added.length = 0 await bot.onNewChatItems(customerMessage("/team")) - expectSentToGroup(CUSTOMER_GROUP_ID, "team member has been added") + expectSentToGroup(CUSTOMER_GROUP_ID, "We will reply within") expectMemberAdded(CUSTOMER_GROUP_ID, TEAM_MEMBER_1_ID) }) test("/team after all team members left (TEAM, msg was sent) → re-adds members", async () => { await reachTeamPending() - addBotMessage("A team member has been added") + addBotMessage("We will reply within 24 hours.") chat.members.set(CUSTOMER_GROUP_ID, [makeTeamMember(TEAM_MEMBER_1_ID, "Alice")]) addTeamMemberMessageToHistory("Hi, how can I help?", TEAM_MEMBER_1_ID) await bot.onNewChatItems(teamMemberMessage("Hi, how can I help?")) @@ -944,7 +944,7 @@ describe("Team Member Lifecycle", () => { chat.added.length = 0 await bot.onNewChatItems(customerMessage("/team")) - expectSentToGroup(CUSTOMER_GROUP_ID, "team member has been added") + expectSentToGroup(CUSTOMER_GROUP_ID, "We will reply within") expectMemberAdded(CUSTOMER_GROUP_ID, TEAM_MEMBER_1_ID) }) }) @@ -1057,7 +1057,7 @@ describe("Card Format & State Derivation", () => { beforeEach(() => setup()) test("QUEUE state derived when no Grok or team members", async () => { - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") const state = await cards.deriveState(CUSTOMER_GROUP_ID) expect(state).toBe("QUEUE") }) @@ -1118,7 +1118,7 @@ describe("/join Command (Team Group)", () => { test("customer sending /join in customer group → treated as normal message", async () => { await bot.onNewChatItems(customerMessage("/join 50:Test")) - expectSentToGroup(CUSTOMER_GROUP_ID, "The team can see your message") + expectSentToGroup(CUSTOMER_GROUP_ID, "The team will reply to your message") }) }) @@ -1313,7 +1313,7 @@ describe("Error Handling", () => { test("apiAddMember fails (Grok invite) → grokUnavailableMessage", async () => { await reachQueue() - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") chat.apiAddMemberWillFail() await bot.onNewChatItems(customerMessage("/grok")) await bot.flush() @@ -1322,7 +1322,7 @@ describe("Error Handling", () => { test("groupDuplicateMember on Grok invite → only inviting message, no result", async () => { await reachQueue() - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") chat.apiAddMemberWillFail({chatError: {errorType: {type: "groupDuplicateMember"}}}) const sentBefore = chat.sent.length await bot.onNewChatItems(customerMessage("/grok")) @@ -1330,13 +1330,13 @@ describe("Error Handling", () => { // Only the "Inviting Grok" message is sent — no activated/unavailable result expect(chat.sent.length).toBe(sentBefore + 1) expectSentToGroup(CUSTOMER_GROUP_ID, "Inviting Grok") - expectNotSentToGroup(CUSTOMER_GROUP_ID, "now chatting with Grok") + expectNotSentToGroup(CUSTOMER_GROUP_ID, "You are chatting with Grok") expectNotSentToGroup(CUSTOMER_GROUP_ID, "temporarily unavailable") }) test("groupDuplicateMember on /team → apiListMembers fallback", async () => { await reachQueue() - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") // First team member add succeeds, second fails with groupDuplicateMember let callCount = 0 @@ -1353,7 +1353,7 @@ describe("Error Handling", () => { } await bot.onNewChatItems(customerMessage("/team")) - expectSentToGroup(CUSTOMER_GROUP_ID, "team member has been added") + expectSentToGroup(CUSTOMER_GROUP_ID, "We will reply within") }) }) @@ -1417,7 +1417,7 @@ describe("Grok Join Flow", () => { // First need to set up a pending grok join // Simulate the main profile side: add Grok to a group await reachQueue() - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") // This kicks off activateGrok which adds member and waits const joinComplete = new Promise(async (resolve) => { @@ -1497,19 +1497,19 @@ describe("Grok Join Flow", () => { }) await reachQueue() - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") const botPromise = bot.onNewChatItems(customerMessage("/grok")) await joinComplete await botPromise await bot.flush() expect(chat.joined).toContain(GROK_LOCAL_GROUP_ID) - expectSentToGroup(CUSTOMER_GROUP_ID, "now chatting with Grok") + expectSentToGroup(CUSTOMER_GROUP_ID, "You are chatting with Grok") }) test("per-message responses suppressed during activateGrok initial response", async () => { await reachQueue() - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") // Customer's message visible in Grok's view (activateGrok reads it for initial response) addCustomerMessageToHistory("Hello, I need help", GROK_LOCAL_GROUP_ID) @@ -1607,13 +1607,13 @@ describe("End-to-End Flows", () => { test("WELCOME → QUEUE → /team → TEAM-PENDING → team msg → TEAM", async () => { await bot.onNewChatItems(customerMessage("Help me")) - expectSentToGroup(CUSTOMER_GROUP_ID, "The team can see your message") - addBotMessage("The team can see your message") + expectSentToGroup(CUSTOMER_GROUP_ID, "The team will reply to your message") + addBotMessage("The team will reply to your message") await bot.onNewChatItems(customerMessage("/team")) - expectSentToGroup(CUSTOMER_GROUP_ID, "team member has been added") + expectSentToGroup(CUSTOMER_GROUP_ID, "We will reply within") expectMemberAdded(CUSTOMER_GROUP_ID, TEAM_MEMBER_1_ID) - addBotMessage("A team member has been added") + addBotMessage("We will reply within 24 hours.") chat.members.set(CUSTOMER_GROUP_ID, [makeTeamMember(TEAM_MEMBER_1_ID, "Alice")]) const pendingState = await cards.deriveState(CUSTOMER_GROUP_ID) @@ -1632,8 +1632,8 @@ describe("End-to-End Flows", () => { await joinPromise await bot.flush() - expectSentToGroup(CUSTOMER_GROUP_ID, "now chatting with Grok") - expectNotSentToGroup(CUSTOMER_GROUP_ID, "The team can see your message") + expectSentToGroup(CUSTOMER_GROUP_ID, "You are chatting with Grok") + expectNotSentToGroup(CUSTOMER_GROUP_ID, "The team will reply to your message") expect(chat.sentTo(TEAM_GROUP_ID).length).toBeGreaterThan(0) }) @@ -1657,8 +1657,8 @@ describe("End-to-End Flows", () => { chatItems: [{chatInfo: {type: "group", groupInfo: makeGroupInfo(GROUP_B, {customerId: "cust-b"})}, chatItem: ciB}], }) - expectSentToGroup(GROUP_A, "The team can see your message") - expectSentToGroup(GROUP_B, "The team can see your message") + expectSentToGroup(GROUP_A, "The team will reply to your message") + expectSentToGroup(GROUP_B, "The team will reply to your message") }) }) @@ -1668,8 +1668,8 @@ describe("Message Templates", () => { expect(welcomeMessage.length).toBeGreaterThan(0) }) - test("grokActivatedMessage mentions Grok can see earlier messages", () => { - expect(grokActivatedMessage).toContain("Grok can see your earlier messages") + test("grokActivatedMessage mentions chatting with Grok", () => { + expect(grokActivatedMessage).toContain("chatting with Grok") }) test("teamLockedMessage mentions team mode", () => { @@ -1685,20 +1685,20 @@ describe("Message Templates", () => { describe("isFirstCustomerMessage detection", () => { beforeEach(() => setup()) - test("detects 'The team can see your message' as queue message", async () => { - addBotMessage("The team can see your message. A reply may take up to 24 hours.") + test("detects 'The team will reply to your message' as queue message", async () => { + addBotMessage("The team will reply to your message within 24 hours.") const isFirst = await cards.isFirstCustomerMessage(CUSTOMER_GROUP_ID) expect(isFirst).toBe(false) }) - test("detects 'now chatting with Grok' as grok activation", async () => { - addBotMessage("You are now chatting with Grok.") + test("detects 'You are chatting with Grok' as grok activation", async () => { + addBotMessage("*You are chatting with Grok* - use any language.") const isFirst = await cards.isFirstCustomerMessage(CUSTOMER_GROUP_ID) expect(isFirst).toBe(false) }) - test("detects 'team member has been added' as team activation", async () => { - addBotMessage("A team member has been added and will reply within 24 hours.") + test("detects 'We will reply within' as team activation", async () => { + addBotMessage("We will reply within 24 hours.") const isFirst = await cards.isFirstCustomerMessage(CUSTOMER_GROUP_ID) expect(isFirst).toBe(false) }) @@ -1807,11 +1807,11 @@ describe("Card Preview Sender Prefixes", () => { const gi = makeGroupInfo(CUSTOMER_GROUP_ID, {displayName: "Alice"}) chat.groups.set(CUSTOMER_GROUP_ID, gi) addCustomerMessageToHistory("Hello") - addBotMessage("The team can see your message") + addBotMessage("The team will reply to your message") addCustomerMessageToHistory("Thanks") await cards.createCard(CUSTOMER_GROUP_ID, gi) const preview = getCardPreview() - expect(preview).not.toContain("The team can see your message") + expect(preview).not.toContain("The team will reply to your message") // Both customer messages are from the same sender — only first prefixed expect(preview).toContain("Alice: Hello") expect(preview).toContain("!3 /! Thanks") diff --git a/apps/simplex-support-bot/src/bot.ts b/apps/simplex-support-bot/src/bot.ts index 134693a534..4b1228cbff 100644 --- a/apps/simplex-support-bot/src/bot.ts +++ b/apps/simplex-support-bot/src/bot.ts @@ -666,11 +666,11 @@ export class SupportBot { } if (!hasTeamBefore) { - // Check by scanning history for "team member has been added" AND verify team still present + // Check by scanning history for the teamAddedMessage AND verify team still present const chat = await this.cards.getChat(groupId, 50) const alreadyAdded = chat.chatItems.some((ci: T.ChatItem) => ci.chatDir.type === "groupSnd" - && util.ciContentText(ci)?.includes("team member has been added") + && util.ciContentText(ci)?.includes("We will reply within") ) if (alreadyAdded) { const {teamMembers} = await this.cards.getGroupComposition(groupId) diff --git a/apps/simplex-support-bot/src/cards.ts b/apps/simplex-support-bot/src/cards.ts index cecbfe5698..5649eb5805 100644 --- a/apps/simplex-support-bot/src/cards.ts +++ b/apps/simplex-support-bot/src/cards.ts @@ -169,9 +169,9 @@ export class CardManager { return !chat.chatItems.some((ci: T.ChatItem) => { if (ci.chatDir.type !== "groupSnd") return false const text = util.ciContentText(ci) - return text?.includes("The team can see your message") - || text?.includes("now chatting with Grok") - || text?.includes("team member has been added") + return text?.includes("The team will reply to your message") + || text?.includes("chatting with Grok") + || text?.includes("We will reply within") || text?.includes("team member has already been invited") }) } diff --git a/apps/simplex-support-bot/src/messages.ts b/apps/simplex-support-bot/src/messages.ts index 40005dad6b..9952ccf8ce 100644 --- a/apps/simplex-support-bot/src/messages.ts +++ b/apps/simplex-support-bot/src/messages.ts @@ -14,7 +14,7 @@ If your question is about SimpleX, click /grok for an *instant Grok answer*. Send /team to switch back.` } -export const grokActivatedMessage = `*You chatting with Grok* - use any language.` +export const grokActivatedMessage = `*You are chatting with Grok* - use any language.` export function teamAddedMessage(timezone: string, grokPresent: boolean): string { const hours = isWeekend(timezone) ? "48" : "24"