mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat(tools): added support for ms teams attachments (#412)
* added support for attachments in teams * ran linter * fixed small error * run lint * removed comments --------- Co-authored-by: Adam Gough <adamgough@Adams-MacBook-Pro.local>
This commit is contained in:
+2
-2
@@ -381,8 +381,8 @@ export function TeamsMessageSelector({
|
||||
setSelectedChannelId(channel.channelId || '')
|
||||
setSelectedChatId('')
|
||||
setSelectedMessage(channel)
|
||||
setSelectedMessageId(channel.id)
|
||||
onChange(channel.id, channel)
|
||||
setSelectedMessageId(channel.channelId || '')
|
||||
onChange(channel.channelId || '', channel)
|
||||
onMessageInfoChange?.(channel)
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { MicrosoftTeamsAttachment } from './types'
|
||||
|
||||
/**
|
||||
* Transform raw attachment data from Microsoft Graph API
|
||||
*/
|
||||
function transformAttachment(rawAttachment: any): MicrosoftTeamsAttachment {
|
||||
return {
|
||||
id: rawAttachment.id,
|
||||
contentType: rawAttachment.contentType,
|
||||
contentUrl: rawAttachment.contentUrl,
|
||||
content: rawAttachment.content,
|
||||
name: rawAttachment.name,
|
||||
thumbnailUrl: rawAttachment.thumbnailUrl,
|
||||
size: rawAttachment.size,
|
||||
sourceUrl: rawAttachment.sourceUrl,
|
||||
providerType: rawAttachment.providerType,
|
||||
item: rawAttachment.item,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract attachments from message data
|
||||
* Returns all attachments without any content processing
|
||||
*/
|
||||
export function extractMessageAttachments(message: any): MicrosoftTeamsAttachment[] {
|
||||
const attachments = (message.attachments || []).map(transformAttachment)
|
||||
|
||||
return attachments
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import type { ToolConfig } from '../types'
|
||||
import { extractMessageAttachments } from './attachment-utils'
|
||||
import type { MicrosoftTeamsReadResponse, MicrosoftTeamsToolParams } from './types'
|
||||
|
||||
const logger = createLogger('MicrosoftTeamsReadChannel')
|
||||
|
||||
export const readChannelTool: ToolConfig<MicrosoftTeamsToolParams, MicrosoftTeamsReadResponse> = {
|
||||
id: 'microsoft_teams_read_channel',
|
||||
name: 'Read Microsoft Teams Channel',
|
||||
description: 'Read content from a Microsoft Teams channel',
|
||||
version: '1.0',
|
||||
version: '1.1',
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'microsoft-teams',
|
||||
@@ -60,10 +64,16 @@ export const readChannelTool: ToolConfig<MicrosoftTeamsToolParams, MicrosoftTeam
|
||||
}
|
||||
},
|
||||
},
|
||||
transformResponse: async (response: Response) => {
|
||||
transformResponse: async (response: Response, params?: MicrosoftTeamsToolParams) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Failed to read Microsoft Teams channel: ${errorText}`)
|
||||
logger.error(
|
||||
`Microsoft Teams channel API error: ${response.status} ${response.statusText}`,
|
||||
errorText
|
||||
)
|
||||
throw new Error(
|
||||
`Failed to read Microsoft Teams channel: ${response.status} ${response.statusText} - ${errorText}`
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
@@ -81,36 +91,88 @@ export const readChannelTool: ToolConfig<MicrosoftTeamsToolParams, MicrosoftTeam
|
||||
channelId: '',
|
||||
messageCount: 0,
|
||||
messages: [],
|
||||
totalAttachments: 0,
|
||||
attachmentTypes: [],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Format the messages into a readable text
|
||||
const formattedMessages = messages
|
||||
.map((message: any) => {
|
||||
if (!params?.teamId || !params?.channelId) {
|
||||
throw new Error('Missing required parameters: teamId and channelId')
|
||||
}
|
||||
// Process messages with attachments
|
||||
const processedMessages = messages.map((message: any, index: number) => {
|
||||
try {
|
||||
const content = message.body?.content || 'No content'
|
||||
const sender = message.from?.user?.displayName || 'Unknown sender'
|
||||
const timestamp = message.createdDateTime
|
||||
? new Date(message.createdDateTime).toLocaleString()
|
||||
const messageId = message.id
|
||||
|
||||
const attachments = extractMessageAttachments(message)
|
||||
|
||||
let sender = 'Unknown'
|
||||
if (message.from?.user?.displayName) {
|
||||
sender = message.from.user.displayName
|
||||
} else if (message.messageType === 'systemEventMessage') {
|
||||
sender = 'System'
|
||||
}
|
||||
|
||||
return {
|
||||
id: messageId,
|
||||
content: content,
|
||||
sender,
|
||||
timestamp: message.createdDateTime,
|
||||
messageType: message.messageType || 'message',
|
||||
attachments,
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error processing message at index ${index}:`, error)
|
||||
return {
|
||||
id: message.id || `unknown-${index}`,
|
||||
content: 'Error processing message',
|
||||
sender: 'Unknown',
|
||||
timestamp: message.createdDateTime || new Date().toISOString(),
|
||||
messageType: 'error',
|
||||
attachments: [],
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Format the messages into a readable text (no attachment info in content)
|
||||
const formattedMessages = processedMessages
|
||||
.map((message: any) => {
|
||||
const sender = message.sender
|
||||
const timestamp = message.timestamp
|
||||
? new Date(message.timestamp).toLocaleString()
|
||||
: 'Unknown time'
|
||||
|
||||
return `[${timestamp}] ${sender}: ${content}`
|
||||
return `[${timestamp}] ${sender}: ${message.content}`
|
||||
})
|
||||
.join('\n\n')
|
||||
|
||||
// Calculate attachment statistics
|
||||
const allAttachments = processedMessages.flatMap((msg: any) => msg.attachments || [])
|
||||
const attachmentTypes: string[] = []
|
||||
const seenTypes = new Set<string>()
|
||||
|
||||
allAttachments.forEach((att: any) => {
|
||||
if (
|
||||
att.contentType &&
|
||||
typeof att.contentType === 'string' &&
|
||||
!seenTypes.has(att.contentType)
|
||||
) {
|
||||
attachmentTypes.push(att.contentType)
|
||||
seenTypes.add(att.contentType)
|
||||
}
|
||||
})
|
||||
|
||||
// Create document metadata
|
||||
const metadata = {
|
||||
teamId: messages[0]?.channelIdentity?.teamId || '',
|
||||
channelId: messages[0]?.channelIdentity?.channelId || '',
|
||||
teamId: messages[0]?.channelIdentity?.teamId || params.teamId || '',
|
||||
channelId: messages[0]?.channelIdentity?.channelId || params.channelId || '',
|
||||
messageCount: messages.length,
|
||||
messages: messages.map((msg: any) => ({
|
||||
id: msg.id,
|
||||
content: msg.body?.content || '',
|
||||
sender: msg.from?.user?.displayName || 'Unknown',
|
||||
timestamp: msg.createdDateTime,
|
||||
messageType: msg.messageType || 'message',
|
||||
})),
|
||||
totalAttachments: allAttachments.length,
|
||||
attachmentTypes,
|
||||
messages: processedMessages,
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import type { ToolConfig } from '../types'
|
||||
import { extractMessageAttachments } from './attachment-utils'
|
||||
import type { MicrosoftTeamsReadResponse, MicrosoftTeamsToolParams } from './types'
|
||||
|
||||
export const readChatTool: ToolConfig<MicrosoftTeamsToolParams, MicrosoftTeamsReadResponse> = {
|
||||
id: 'microsoft_teams_read_chat',
|
||||
name: 'Read Microsoft Teams Chat',
|
||||
description: 'Read content from a Microsoft Teams chat',
|
||||
version: '1.0',
|
||||
version: '1.1',
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'microsoft-teams',
|
||||
@@ -44,7 +45,7 @@ export const readChatTool: ToolConfig<MicrosoftTeamsToolParams, MicrosoftTeamsRe
|
||||
}
|
||||
},
|
||||
},
|
||||
transformResponse: async (response: Response) => {
|
||||
transformResponse: async (response: Response, params?: MicrosoftTeamsToolParams) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Failed to read Microsoft Teams chat: ${errorText}`)
|
||||
@@ -64,35 +65,70 @@ export const readChatTool: ToolConfig<MicrosoftTeamsToolParams, MicrosoftTeamsRe
|
||||
chatId: '',
|
||||
messageCount: 0,
|
||||
messages: [],
|
||||
totalAttachments: 0,
|
||||
attachmentTypes: [],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Format the messages into a readable text
|
||||
const formattedMessages = messages
|
||||
if (!params?.chatId) {
|
||||
throw new Error('Missing required parameter: chatId')
|
||||
}
|
||||
|
||||
// Process messages with attachments
|
||||
const processedMessages = messages.map((message: any) => {
|
||||
const content = message.body?.content || 'No content'
|
||||
const messageId = message.id
|
||||
|
||||
// Extract attachments without any content processing
|
||||
const attachments = extractMessageAttachments(message)
|
||||
|
||||
return {
|
||||
id: messageId,
|
||||
content: content, // Keep original content without modification
|
||||
sender: message.from?.user?.displayName || 'Unknown',
|
||||
timestamp: message.createdDateTime,
|
||||
messageType: message.messageType || 'message',
|
||||
attachments, // Attachments only stored here
|
||||
}
|
||||
})
|
||||
|
||||
// Format the messages into a readable text (no attachment info in content)
|
||||
const formattedMessages = processedMessages
|
||||
.map((message: any) => {
|
||||
const content = message.body?.content || 'No content'
|
||||
const sender = message.from?.user?.displayName || 'Unknown sender'
|
||||
const timestamp = message.createdDateTime
|
||||
? new Date(message.createdDateTime).toLocaleString()
|
||||
const sender = message.sender
|
||||
const timestamp = message.timestamp
|
||||
? new Date(message.timestamp).toLocaleString()
|
||||
: 'Unknown time'
|
||||
|
||||
return `[${timestamp}] ${sender}: ${content}`
|
||||
return `[${timestamp}] ${sender}: ${message.content}`
|
||||
})
|
||||
.join('\n\n')
|
||||
|
||||
// Calculate attachment statistics
|
||||
const allAttachments = processedMessages.flatMap((msg: any) => msg.attachments || [])
|
||||
const attachmentTypes: string[] = []
|
||||
const seenTypes = new Set<string>()
|
||||
|
||||
allAttachments.forEach((att: any) => {
|
||||
if (
|
||||
att.contentType &&
|
||||
typeof att.contentType === 'string' &&
|
||||
!seenTypes.has(att.contentType)
|
||||
) {
|
||||
attachmentTypes.push(att.contentType)
|
||||
seenTypes.add(att.contentType)
|
||||
}
|
||||
})
|
||||
|
||||
// Create document metadata
|
||||
const metadata = {
|
||||
chatId: messages[0]?.chatId || '',
|
||||
chatId: messages[0]?.chatId || params.chatId || '',
|
||||
messageCount: messages.length,
|
||||
messages: messages.map((msg: any) => ({
|
||||
id: msg.id,
|
||||
content: msg.body?.content || '',
|
||||
sender: msg.from?.user?.displayName || 'Unknown',
|
||||
timestamp: msg.createdDateTime,
|
||||
messageType: msg.messageType || 'message',
|
||||
})),
|
||||
totalAttachments: allAttachments.length,
|
||||
attachmentTypes,
|
||||
messages: processedMessages,
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
import type { ToolResponse } from '../types'
|
||||
|
||||
export interface MicrosoftTeamsAttachment {
|
||||
id: string
|
||||
contentType: string
|
||||
contentUrl?: string
|
||||
content?: string
|
||||
name?: string
|
||||
thumbnailUrl?: string
|
||||
size?: number
|
||||
sourceUrl?: string
|
||||
providerType?: string
|
||||
item?: any
|
||||
}
|
||||
|
||||
export interface MicrosoftTeamsMetadata {
|
||||
messageId?: string
|
||||
channelId?: string
|
||||
@@ -7,7 +20,6 @@ export interface MicrosoftTeamsMetadata {
|
||||
chatId?: string
|
||||
content?: string
|
||||
createdTime?: string
|
||||
modifiedTime?: string
|
||||
url?: string
|
||||
messageCount?: number
|
||||
messages?: Array<{
|
||||
@@ -16,7 +28,11 @@ export interface MicrosoftTeamsMetadata {
|
||||
sender: string
|
||||
timestamp: string
|
||||
messageType: string
|
||||
attachments?: MicrosoftTeamsAttachment[]
|
||||
}>
|
||||
// Global attachments summary
|
||||
totalAttachments?: number
|
||||
attachmentTypes?: string[]
|
||||
}
|
||||
|
||||
export interface MicrosoftTeamsReadResponse extends ToolResponse {
|
||||
|
||||
@@ -44,11 +44,9 @@ export const writeChannelTool: ToolConfig<MicrosoftTeamsToolParams, MicrosoftTea
|
||||
throw new Error('Channel ID is required')
|
||||
}
|
||||
|
||||
// URL encode the IDs to handle special characters
|
||||
const encodedTeamId = encodeURIComponent(teamId)
|
||||
const encodedChannelId = encodeURIComponent(channelId)
|
||||
|
||||
// Send a message to a channel
|
||||
const url = `https://graph.microsoft.com/v1.0/teams/${encodedTeamId}/channels/${encodedChannelId}/messages`
|
||||
|
||||
return url
|
||||
|
||||
Reference in New Issue
Block a user