@@ -68,6 +68,7 @@ import os from "os"
6868import path from "path"
6969
7070import extract from "extract-zip"
71+ import { createTeamsAdapter } from "@chat-adapter/teams"
7172import { context , docIds } from "@budibase/backend-core"
7273import { generator } from "@budibase/backend-core/tests"
7374import { ChatCommands } from "@budibase/shared-core"
@@ -87,6 +88,7 @@ import { webhookChat } from "../../../controllers/ai/chatConversations"
8788const { getMockChatOptions, resetMockChatState, setMockPostEphemeralResult } =
8889 jest . requireActual ( "chat" ) as ChatMockModule
8990const mockedWebhookChat = webhookChat as jest . MockedFunction < typeof webhookChat >
91+ const mockedCreateTeamsAdapter = jest . mocked ( createTeamsAdapter )
9092const mockedGetFileUrlForAgent = jest . mocked ( sdk . ai . rag . getFileUrlForAgent )
9193const TEAMS_APP_ID = generator . guid ( )
9294
@@ -110,6 +112,7 @@ describe("agent teams integration provisioning", () => {
110112 "test-config"
111113 )
112114 mockedWebhookChat . mockClear ( )
115+ mockedCreateTeamsAdapter . mockClear ( )
113116 mockedGetFileUrlForAgent . mockReset ( )
114117 resetMockChatState ( )
115118 } )
@@ -524,6 +527,7 @@ describe("agent teams integration provisioning", () => {
524527
525528 expect ( response . body . error ) . toEqual ( "Invalid Microsoft Teams service URL" )
526529 expect ( mockedWebhookChat ) . not . toHaveBeenCalled ( )
530+ expect ( mockedCreateTeamsAdapter ) . not . toHaveBeenCalled ( )
527531 } )
528532
529533 it ( `returns a private link prompt for ${ ChatCommands . LINK } and /${ ChatCommands . LINK } commands` , async ( ) => {
@@ -800,56 +804,86 @@ describe("agent teams integration provisioning", () => {
800804 expect ( mockedWebhookChat ) . toHaveBeenCalledTimes ( 1 )
801805 } )
802806
803- it ( "appends downloadable RAG source links to Teams personal replies" , async ( ) => {
804- mockedGetFileUrlForAgent . mockResolvedValue (
805- "/files/signed/prod-budi-app-assets/source.pdf"
806- )
807- mockedWebhookChat . mockResolvedValueOnce ( {
808- messages : [
809- {
810- id : "assistant-1" ,
811- role : "assistant" ,
812- parts : [ { type : "text" , text : "Answer with sources" } ] ,
813- } ,
814- ] as any ,
815- assistantText : "Answer with sources" ,
816- ragSources : [
817- {
818- sourceId : "source-1" ,
819- fileId : "file-1" ,
820- filename : "Source [One]\n@Draft.pdf" ,
821- } ,
822- ] ,
823- title : "Mock conversation" ,
824- } )
807+ it . each ( [ false , true ] ) (
808+ "sends personal reply sources through the activity service URL (streaming: %s)" ,
809+ async streaming => {
810+ const serviceUrl = new URL (
811+ "/emea/" ,
812+ DEFAULT_MSTEAMS_SERVICE_URL
813+ ) . toString ( )
814+ mockedGetFileUrlForAgent . mockResolvedValue (
815+ "/files/signed/prod-budi-app-assets/source.pdf"
816+ )
817+ mockedWebhookChat . mockImplementationOnce (
818+ async ( { onAssistantStream } ) => {
819+ if ( streaming ) {
820+ async function * sourceAnswerStream ( ) {
821+ yield "Answer with "
822+ yield "sources"
823+ }
824+ await onAssistantStream ! ( sourceAnswerStream ( ) )
825+ }
826+ return {
827+ messages : [
828+ {
829+ id : "assistant-1" ,
830+ role : "assistant" ,
831+ parts : [ { type : "text" , text : "Answer with sources" } ] ,
832+ } ,
833+ ] ,
834+ assistantText : "Answer with sources" ,
835+ allowKnowledgeSourceDownload : true ,
836+ ragSources : [
837+ {
838+ sourceId : "source-1" ,
839+ fileId : "file-1" ,
840+ filename : "Source [One]\n@Draft.pdf" ,
841+ } ,
842+ ] ,
843+ title : "Mock conversation" ,
844+ }
845+ }
846+ )
825847
826- const { agent, linkExternalUser } = await setupProvisionedTeamsAgent ( )
827- const path = `/api/webhooks/ms-teams/${ config . getProdWorkspaceId ( ) } /${ agent . _id } `
828- await linkExternalUser ( "user-1" )
848+ const { agent, linkExternalUser } = await setupProvisionedTeamsAgent ( )
849+ const path = `/api/webhooks/ms-teams/${ config . getProdWorkspaceId ( ) } /${ agent . _id } `
850+ await linkExternalUser ( "user-1" )
829851
830- const response = await postTeamsMessage ( {
831- path,
832- body : {
833- id : "activity-rag-personal" ,
834- type : "message" ,
835- text : "hello teams" ,
836- from : { id : "user-1" , name : "Teams User" } ,
837- conversation : { id : "conversation-1" , conversationType : "personal" } ,
838- channelData : { tenant : { id : "tenant-1" } } ,
839- } ,
840- } )
852+ const response = await postTeamsMessage ( {
853+ path,
854+ body : {
855+ id : "activity-rag-personal" ,
856+ serviceUrl,
857+ type : "message" ,
858+ text : "hello teams" ,
859+ from : { id : "user-1" , name : "Teams User" } ,
860+ conversation : {
861+ id : "conversation-1" ,
862+ conversationType : "personal" ,
863+ } ,
864+ channelData : { tenant : { id : "tenant-1" } } ,
865+ } ,
866+ } )
841867
842- expect ( response . body . messages ) . toContain ( "Answer with sources" )
843- const cardMessage = response . body . messages . find ( ( message : string ) =>
844- message . includes ( "Source One Draft.pdf" )
845- )
846- expect ( cardMessage ) . toContain ( '"title":"Sources"' )
847- expect ( cardMessage ) . toContain (
848- "http://localhost:10000/files/signed/prod-budi-app-assets/source.pdf"
849- )
850- expect ( mockedWebhookChat ) . toHaveBeenCalledTimes ( 1 )
851- expect ( mockedGetFileUrlForAgent ) . toHaveBeenCalledWith ( agent . _id , "file-1" )
852- } )
868+ expect ( response . body . messages ) . toHaveLength ( 2 )
869+ expect ( response . body . messages [ 0 ] ) . toEqual ( "Answer with sources" )
870+ expect ( mockedCreateTeamsAdapter ) . toHaveBeenLastCalledWith (
871+ expect . objectContaining ( { apiUrl : serviceUrl } )
872+ )
873+ const cardMessage = response . body . messages . find ( ( message : string ) =>
874+ message . includes ( "Source One Draft.pdf" )
875+ )
876+ expect ( cardMessage ) . toContain ( '"title":"Sources"' )
877+ expect ( cardMessage ) . toContain (
878+ "http://localhost:10000/files/signed/prod-budi-app-assets/source.pdf"
879+ )
880+ expect ( mockedWebhookChat ) . toHaveBeenCalledTimes ( 1 )
881+ expect ( mockedGetFileUrlForAgent ) . toHaveBeenCalledWith (
882+ agent . _id ,
883+ "file-1"
884+ )
885+ }
886+ )
853887
854888 it ( "does not append RAG source links to Teams channel replies" , async ( ) => {
855889 mockedWebhookChat . mockResolvedValueOnce ( {
0 commit comments