mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-22 09:01:09 +03:00
30c4180d97
* add teams, gmail, outlook tools * update docs link * update credentials for oauth2 * add jira tool * add google drive, google calendar, google sheets tools, powerpoint, excel, word doc loader * update jira logo * Refactor Gmail and Outlook tools to remove maxOutputLength parameter and enhance request handling. Update response formatting to include parameters in the output. Adjust Google Drive tools to simplify success messages by removing unnecessary parameter details.
1757 lines
59 KiB
TypeScript
1757 lines
59 KiB
TypeScript
import { z } from 'zod'
|
|
import { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager'
|
|
import { DynamicStructuredTool, DynamicStructuredToolInput } from '../OpenAPIToolkit/core'
|
|
import { TOOL_ARGS_PREFIX } from '../../../src/agents'
|
|
|
|
interface TeamsToolOptions {
|
|
accessToken: string
|
|
actions: string[]
|
|
defaultParams: any
|
|
type: string
|
|
}
|
|
|
|
const BASE_URL = 'https://graph.microsoft.com/v1.0'
|
|
|
|
// Helper function to make Graph API requests
|
|
async function makeGraphRequest(
|
|
endpoint: string,
|
|
method: 'GET' | 'POST' | 'PATCH' | 'DELETE' = 'GET',
|
|
body?: any,
|
|
accessToken?: string
|
|
): Promise<any> {
|
|
const headers: Record<string, string> = {
|
|
Authorization: `Bearer ${accessToken}`,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
|
|
const config: RequestInit = {
|
|
method,
|
|
headers
|
|
}
|
|
|
|
if (body && (method === 'POST' || method === 'PATCH')) {
|
|
config.body = JSON.stringify(body)
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`${BASE_URL}${endpoint}`, config)
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text()
|
|
throw new Error(`Microsoft Graph API error: ${response.status} ${response.statusText} - ${errorText}`)
|
|
}
|
|
|
|
// Handle empty responses for DELETE operations
|
|
if (method === 'DELETE' || response.status === 204) {
|
|
return { success: true, message: 'Operation completed successfully' }
|
|
}
|
|
|
|
return await response.json()
|
|
} catch (error) {
|
|
throw new Error(`Microsoft Graph request failed: ${error instanceof Error ? error.message : 'Unknown error'}`)
|
|
}
|
|
}
|
|
|
|
// Base Teams Tool class
|
|
abstract class BaseTeamsTool extends DynamicStructuredTool {
|
|
accessToken = ''
|
|
protected defaultParams: any
|
|
|
|
constructor(args: DynamicStructuredToolInput<any> & { accessToken?: string; defaultParams?: any }) {
|
|
super(args)
|
|
this.accessToken = args.accessToken ?? ''
|
|
this.defaultParams = args.defaultParams || {}
|
|
}
|
|
|
|
protected async makeTeamsRequest(endpoint: string, method: string = 'GET', body?: any) {
|
|
return await makeGraphRequest(endpoint, method as any, body, this.accessToken)
|
|
}
|
|
|
|
protected formatResponse(data: any, params: any): string {
|
|
return JSON.stringify(data) + TOOL_ARGS_PREFIX + JSON.stringify(params)
|
|
}
|
|
|
|
// Abstract method that must be implemented by subclasses
|
|
protected abstract _call(arg: any, runManager?: CallbackManagerForToolRun, parentConfig?: any): Promise<string>
|
|
}
|
|
|
|
// CHANNEL TOOLS
|
|
|
|
class ListChannelsTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'list_channels',
|
|
description: 'List all channels in a team',
|
|
schema: z.object({
|
|
teamId: z.string().describe('ID of the team to list channels from'),
|
|
maxResults: z.number().optional().default(50).describe('Maximum number of channels to return')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'GET',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { teamId, maxResults = 50 } = params
|
|
|
|
if (!teamId) {
|
|
throw new Error('Team ID is required to list channels')
|
|
}
|
|
|
|
try {
|
|
const endpoint = `/teams/${teamId}/channels`
|
|
const result = await this.makeTeamsRequest(endpoint)
|
|
|
|
// Filter results to maxResults on client side since $top is not supported
|
|
const channels = result.value || []
|
|
const limitedChannels = channels.slice(0, maxResults)
|
|
|
|
const responseData = {
|
|
success: true,
|
|
channels: limitedChannels,
|
|
count: limitedChannels.length,
|
|
total: channels.length
|
|
}
|
|
|
|
return this.formatResponse(responseData, params)
|
|
} catch (error) {
|
|
return `Error listing channels: ${error}`
|
|
}
|
|
}
|
|
}
|
|
|
|
class GetChannelTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'get_channel',
|
|
description: 'Get details of a specific channel',
|
|
schema: z.object({
|
|
teamId: z.string().describe('ID of the team that contains the channel'),
|
|
channelId: z.string().describe('ID of the channel to retrieve')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'GET',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { teamId, channelId } = params
|
|
|
|
if (!teamId || !channelId) {
|
|
throw new Error('Both Team ID and Channel ID are required')
|
|
}
|
|
|
|
try {
|
|
const endpoint = `/teams/${teamId}/channels/${channelId}`
|
|
const result = await this.makeTeamsRequest(endpoint)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
channel: result
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error getting channel: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class CreateChannelTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'create_channel',
|
|
description: 'Create a new channel in a team',
|
|
schema: z.object({
|
|
teamId: z.string().describe('ID of the team to create the channel in'),
|
|
displayName: z.string().describe('Display name of the channel'),
|
|
description: z.string().optional().describe('Description of the channel'),
|
|
membershipType: z
|
|
.enum(['standard', 'private', 'shared'])
|
|
.optional()
|
|
.default('standard')
|
|
.describe('Type of channel membership')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'POST',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { teamId, displayName, description, membershipType = 'standard' } = params
|
|
|
|
if (!teamId || !displayName) {
|
|
throw new Error('Team ID and Display Name are required to create a channel')
|
|
}
|
|
|
|
try {
|
|
const body = {
|
|
displayName,
|
|
membershipType,
|
|
...(description && { description })
|
|
}
|
|
|
|
const endpoint = `/teams/${teamId}/channels`
|
|
const result = await this.makeTeamsRequest(endpoint, 'POST', body)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
channel: result,
|
|
message: `Channel "${displayName}" created successfully`
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error creating channel: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class UpdateChannelTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'update_channel',
|
|
description: 'Update an existing channel',
|
|
schema: z.object({
|
|
teamId: z.string().describe('ID of the team that contains the channel'),
|
|
channelId: z.string().describe('ID of the channel to update'),
|
|
displayName: z.string().optional().describe('New display name of the channel'),
|
|
description: z.string().optional().describe('New description of the channel')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'PATCH',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { teamId, channelId, displayName, description } = params
|
|
|
|
if (!teamId || !channelId) {
|
|
throw new Error('Both Team ID and Channel ID are required')
|
|
}
|
|
|
|
try {
|
|
const body: any = {}
|
|
if (displayName) body.displayName = displayName
|
|
if (description) body.description = description
|
|
|
|
if (Object.keys(body).length === 0) {
|
|
throw new Error('At least one field to update must be provided')
|
|
}
|
|
|
|
const endpoint = `/teams/${teamId}/channels/${channelId}`
|
|
await this.makeTeamsRequest(endpoint, 'PATCH', body)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Channel updated successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error updating channel: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class DeleteChannelTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'delete_channel',
|
|
description: 'Delete a channel from a team',
|
|
schema: z.object({
|
|
teamId: z.string().describe('ID of the team that contains the channel'),
|
|
channelId: z.string().describe('ID of the channel to delete')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'DELETE',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { teamId, channelId } = params
|
|
|
|
if (!teamId || !channelId) {
|
|
throw new Error('Both Team ID and Channel ID are required')
|
|
}
|
|
|
|
try {
|
|
const endpoint = `/teams/${teamId}/channels/${channelId}`
|
|
await this.makeTeamsRequest(endpoint, 'DELETE')
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Channel deleted successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error deleting channel: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class ArchiveChannelTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'archive_channel',
|
|
description: 'Archive a channel in a team',
|
|
schema: z.object({
|
|
teamId: z.string().describe('ID of the team that contains the channel'),
|
|
channelId: z.string().describe('ID of the channel to archive')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'POST',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { teamId, channelId } = params
|
|
|
|
if (!teamId || !channelId) {
|
|
throw new Error('Both Team ID and Channel ID are required')
|
|
}
|
|
|
|
try {
|
|
const endpoint = `/teams/${teamId}/channels/${channelId}/archive`
|
|
await this.makeTeamsRequest(endpoint, 'POST', {})
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Channel archived successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error archiving channel: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class UnarchiveChannelTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'unarchive_channel',
|
|
description: 'Unarchive a channel in a team',
|
|
schema: z.object({
|
|
teamId: z.string().describe('ID of the team that contains the channel'),
|
|
channelId: z.string().describe('ID of the channel to unarchive')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'POST',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { teamId, channelId } = params
|
|
|
|
if (!teamId || !channelId) {
|
|
throw new Error('Both Team ID and Channel ID are required')
|
|
}
|
|
|
|
try {
|
|
const endpoint = `/teams/${teamId}/channels/${channelId}/unarchive`
|
|
await this.makeTeamsRequest(endpoint, 'POST', {})
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Channel unarchived successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error unarchiving channel: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class ListChannelMembersTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'list_channel_members',
|
|
description: 'List members of a channel',
|
|
schema: z.object({
|
|
teamId: z.string().describe('ID of the team that contains the channel'),
|
|
channelId: z.string().describe('ID of the channel')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'GET',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { teamId, channelId } = params
|
|
|
|
if (!teamId || !channelId) {
|
|
throw new Error('Both Team ID and Channel ID are required')
|
|
}
|
|
|
|
try {
|
|
const endpoint = `/teams/${teamId}/channels/${channelId}/members`
|
|
const result = await this.makeTeamsRequest(endpoint)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
members: result.value || [],
|
|
count: result.value?.length || 0
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error listing channel members: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class AddChannelMemberTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'add_channel_member',
|
|
description: 'Add a member to a channel',
|
|
schema: z.object({
|
|
teamId: z.string().describe('ID of the team that contains the channel'),
|
|
channelId: z.string().describe('ID of the channel'),
|
|
userId: z.string().describe('ID of the user to add')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'POST',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { teamId, channelId, userId } = params
|
|
|
|
if (!teamId || !channelId || !userId) {
|
|
throw new Error('Team ID, Channel ID, and User ID are all required')
|
|
}
|
|
|
|
try {
|
|
const body = {
|
|
'@odata.type': '#microsoft.graph.aadUserConversationMember',
|
|
'user@odata.bind': `https://graph.microsoft.com/v1.0/users('${userId}')`
|
|
}
|
|
|
|
const endpoint = `/teams/${teamId}/channels/${channelId}/members`
|
|
await this.makeTeamsRequest(endpoint, 'POST', body)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Member added to channel successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error adding channel member: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class RemoveChannelMemberTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'remove_channel_member',
|
|
description: 'Remove a member from a channel',
|
|
schema: z.object({
|
|
teamId: z.string().describe('ID of the team that contains the channel'),
|
|
channelId: z.string().describe('ID of the channel'),
|
|
userId: z.string().describe('ID of the user to remove')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'DELETE',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { teamId, channelId, userId } = params
|
|
|
|
if (!teamId || !channelId || !userId) {
|
|
throw new Error('Team ID, Channel ID, and User ID are all required')
|
|
}
|
|
|
|
try {
|
|
// First get the membership ID
|
|
const membersEndpoint = `/teams/${teamId}/channels/${channelId}/members`
|
|
const membersResult = await this.makeTeamsRequest(membersEndpoint)
|
|
|
|
const member = membersResult.value?.find((m: any) => m.userId === userId)
|
|
if (!member) {
|
|
throw new Error('User is not a member of this channel')
|
|
}
|
|
|
|
const endpoint = `/teams/${teamId}/channels/${channelId}/members/${member.id}`
|
|
await this.makeTeamsRequest(endpoint, 'DELETE')
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Member removed from channel successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error removing channel member: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
// CHAT TOOLS
|
|
|
|
class ListChatsTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'list_chats',
|
|
description: 'List all chats for the current user',
|
|
schema: z.object({
|
|
maxResults: z.number().optional().default(50).describe('Maximum number of chats to return')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'GET',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { maxResults = 50 } = params
|
|
|
|
try {
|
|
const endpoint = `/me/chats?$top=${maxResults}`
|
|
const result = await this.makeTeamsRequest(endpoint)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
chats: result.value || [],
|
|
count: result.value?.length || 0
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error listing chats: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class GetChatTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'get_chat',
|
|
description: 'Get details of a specific chat',
|
|
schema: z.object({
|
|
chatId: z.string().describe('ID of the chat to retrieve')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'GET',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatId } = params
|
|
|
|
if (!chatId) {
|
|
throw new Error('Chat ID is required')
|
|
}
|
|
|
|
try {
|
|
const endpoint = `/chats/${chatId}`
|
|
const result = await this.makeTeamsRequest(endpoint)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
chat: result
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error getting chat: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class CreateChatTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'create_chat',
|
|
description: 'Create a new chat',
|
|
schema: z.object({
|
|
chatType: z.enum(['oneOnOne', 'group']).optional().default('group').describe('Type of chat to create'),
|
|
topic: z.string().optional().describe('Topic/subject of the chat (for group chats)'),
|
|
members: z.string().describe('Comma-separated list of user IDs to add to the chat')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'POST',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatType = 'group', topic, members } = params
|
|
|
|
if (!members) {
|
|
throw new Error('Members list is required to create a chat')
|
|
}
|
|
|
|
try {
|
|
const memberIds = members.split(',').map((id: string) => id.trim())
|
|
const chatMembers = memberIds.map((userId: string) => ({
|
|
'@odata.type': '#microsoft.graph.aadUserConversationMember',
|
|
'user@odata.bind': `https://graph.microsoft.com/v1.0/users('${userId}')`
|
|
}))
|
|
|
|
const body: any = {
|
|
chatType,
|
|
members: chatMembers
|
|
}
|
|
|
|
if (topic && chatType === 'group') {
|
|
body.topic = topic
|
|
}
|
|
|
|
const endpoint = '/chats'
|
|
const result = await this.makeTeamsRequest(endpoint, 'POST', body)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
chat: result,
|
|
message: 'Chat created successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error creating chat: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class UpdateChatTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'update_chat',
|
|
description: 'Update an existing chat',
|
|
schema: z.object({
|
|
chatId: z.string().describe('ID of the chat to update'),
|
|
topic: z.string().describe('New topic/subject of the chat')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'PATCH',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatId, topic } = params
|
|
|
|
if (!chatId) {
|
|
throw new Error('Chat ID is required')
|
|
}
|
|
|
|
if (!topic) {
|
|
throw new Error('Topic is required to update a chat')
|
|
}
|
|
|
|
try {
|
|
const body = { topic }
|
|
const endpoint = `/chats/${chatId}`
|
|
await this.makeTeamsRequest(endpoint, 'PATCH', body)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Chat updated successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error updating chat: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class DeleteChatTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'delete_chat',
|
|
description: 'Delete a chat',
|
|
schema: z.object({
|
|
chatId: z.string().describe('ID of the chat to delete')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'DELETE',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatId } = params
|
|
|
|
if (!chatId) {
|
|
throw new Error('Chat ID is required')
|
|
}
|
|
|
|
try {
|
|
const endpoint = `/chats/${chatId}`
|
|
await this.makeTeamsRequest(endpoint, 'DELETE')
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Chat deleted successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error deleting chat: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class ListChatMembersTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'list_chat_members',
|
|
description: 'List members of a chat',
|
|
schema: z.object({
|
|
chatId: z.string().describe('ID of the chat')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'GET',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatId } = params
|
|
|
|
if (!chatId) {
|
|
throw new Error('Chat ID is required')
|
|
}
|
|
|
|
try {
|
|
const endpoint = `/chats/${chatId}/members`
|
|
const result = await this.makeTeamsRequest(endpoint)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
members: result.value || [],
|
|
count: result.value?.length || 0
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error listing chat members: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class AddChatMemberTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'add_chat_member',
|
|
description: 'Add a member to a chat',
|
|
schema: z.object({
|
|
chatId: z.string().describe('ID of the chat'),
|
|
userId: z.string().describe('ID of the user to add')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'POST',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatId, userId } = params
|
|
|
|
if (!chatId || !userId) {
|
|
throw new Error('Both Chat ID and User ID are required')
|
|
}
|
|
|
|
try {
|
|
const body = {
|
|
'@odata.type': '#microsoft.graph.aadUserConversationMember',
|
|
'user@odata.bind': `https://graph.microsoft.com/v1.0/users('${userId}')`
|
|
}
|
|
|
|
const endpoint = `/chats/${chatId}/members`
|
|
await this.makeTeamsRequest(endpoint, 'POST', body)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Member added to chat successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error adding chat member: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class RemoveChatMemberTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'remove_chat_member',
|
|
description: 'Remove a member from a chat',
|
|
schema: z.object({
|
|
chatId: z.string().describe('ID of the chat'),
|
|
userId: z.string().describe('ID of the user to remove')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'DELETE',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatId, userId } = params
|
|
|
|
if (!chatId || !userId) {
|
|
throw new Error('Both Chat ID and User ID are required')
|
|
}
|
|
|
|
try {
|
|
// First get the membership ID
|
|
const membersEndpoint = `/chats/${chatId}/members`
|
|
const membersResult = await this.makeTeamsRequest(membersEndpoint)
|
|
|
|
const member = membersResult.value?.find((m: any) => m.userId === userId)
|
|
if (!member) {
|
|
throw new Error('User is not a member of this chat')
|
|
}
|
|
|
|
const endpoint = `/chats/${chatId}/members/${member.id}`
|
|
await this.makeTeamsRequest(endpoint, 'DELETE')
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Member removed from chat successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error removing chat member: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class PinMessageTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'pin_message',
|
|
description: 'Pin a message in a chat',
|
|
schema: z.object({
|
|
chatId: z.string().describe('ID of the chat'),
|
|
messageId: z.string().describe('ID of the message to pin')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'POST',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatId, messageId } = params
|
|
|
|
if (!chatId || !messageId) {
|
|
throw new Error('Both Chat ID and Message ID are required')
|
|
}
|
|
|
|
try {
|
|
const body = {
|
|
message: {
|
|
'@odata.bind': `https://graph.microsoft.com/v1.0/chats('${chatId}')/messages('${messageId}')`
|
|
}
|
|
}
|
|
|
|
const endpoint = `/chats/${chatId}/pinnedMessages`
|
|
await this.makeTeamsRequest(endpoint, 'POST', body)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Message pinned successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error pinning message: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class UnpinMessageTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'unpin_message',
|
|
description: 'Unpin a message from a chat',
|
|
schema: z.object({
|
|
chatId: z.string().describe('ID of the chat'),
|
|
messageId: z.string().describe('ID of the message to unpin')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'DELETE',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatId, messageId } = params
|
|
|
|
if (!chatId || !messageId) {
|
|
throw new Error('Both Chat ID and Message ID are required')
|
|
}
|
|
|
|
try {
|
|
// First get the pinned messages to find the pinned message ID
|
|
const pinnedEndpoint = `/chats/${chatId}/pinnedMessages`
|
|
const pinnedResult = await this.makeTeamsRequest(pinnedEndpoint)
|
|
|
|
const pinnedMessage = pinnedResult.value?.find((pm: any) => pm.message?.id === messageId)
|
|
if (!pinnedMessage) {
|
|
throw new Error('Message is not pinned in this chat')
|
|
}
|
|
|
|
const endpoint = `/chats/${chatId}/pinnedMessages/${pinnedMessage.id}`
|
|
await this.makeTeamsRequest(endpoint, 'DELETE')
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Message unpinned successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error unpinning message: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
// CHAT MESSAGE TOOLS
|
|
|
|
class ListMessagesTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'list_messages',
|
|
description: 'List messages in a chat or channel',
|
|
schema: z.object({
|
|
chatChannelId: z.string().describe('ID of the chat or channel to list messages from'),
|
|
teamId: z.string().optional().describe('ID of the team (required for channel messages)'),
|
|
maxResults: z.number().optional().default(50).describe('Maximum number of messages to return')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'GET',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatChannelId, teamId, maxResults = 50 } = params
|
|
|
|
if (!chatChannelId) {
|
|
throw new Error('Chat or Channel ID is required')
|
|
}
|
|
|
|
try {
|
|
let endpoint: string
|
|
if (teamId) {
|
|
// Channel messages
|
|
endpoint = `/teams/${teamId}/channels/${chatChannelId}/messages?$top=${maxResults}`
|
|
} else {
|
|
// Chat messages
|
|
endpoint = `/chats/${chatChannelId}/messages?$top=${maxResults}`
|
|
}
|
|
|
|
const result = await this.makeTeamsRequest(endpoint)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
messages: result.value || [],
|
|
count: result.value?.length || 0,
|
|
context: teamId ? 'channel' : 'chat'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error listing messages: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class GetMessageTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'get_message',
|
|
description: 'Get details of a specific message',
|
|
schema: z.object({
|
|
chatChannelId: z.string().describe('ID of the chat or channel'),
|
|
teamId: z.string().optional().describe('ID of the team (required for channel messages)'),
|
|
messageId: z.string().describe('ID of the message to retrieve')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'GET',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatChannelId, teamId, messageId } = params
|
|
|
|
if (!chatChannelId || !messageId) {
|
|
throw new Error('Chat/Channel ID and Message ID are required')
|
|
}
|
|
|
|
try {
|
|
let endpoint: string
|
|
if (teamId) {
|
|
// Channel message
|
|
endpoint = `/teams/${teamId}/channels/${chatChannelId}/messages/${messageId}`
|
|
} else {
|
|
// Chat message
|
|
endpoint = `/chats/${chatChannelId}/messages/${messageId}`
|
|
}
|
|
|
|
const result = await this.makeTeamsRequest(endpoint)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: result,
|
|
context: teamId ? 'channel' : 'chat'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error getting message: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class SendMessageTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'send_message',
|
|
description: 'Send a message to a chat or channel',
|
|
schema: z.object({
|
|
chatChannelId: z.string().describe('ID of the chat or channel to send message to'),
|
|
teamId: z.string().optional().describe('ID of the team (required for channel messages)'),
|
|
messageBody: z.string().describe('Content of the message'),
|
|
contentType: z.enum(['text', 'html']).optional().default('text').describe('Content type of the message')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'POST',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatChannelId, teamId, messageBody, contentType = 'text' } = params
|
|
|
|
if (!chatChannelId || !messageBody) {
|
|
throw new Error('Chat/Channel ID and Message Body are required')
|
|
}
|
|
|
|
try {
|
|
const body = {
|
|
body: {
|
|
contentType,
|
|
content: messageBody
|
|
}
|
|
}
|
|
|
|
let endpoint: string
|
|
if (teamId) {
|
|
// Channel message
|
|
endpoint = `/teams/${teamId}/channels/${chatChannelId}/messages`
|
|
} else {
|
|
// Chat message
|
|
endpoint = `/chats/${chatChannelId}/messages`
|
|
}
|
|
|
|
const result = await this.makeTeamsRequest(endpoint, 'POST', body)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: result,
|
|
context: teamId ? 'channel' : 'chat',
|
|
messageText: 'Message sent successfully'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error sending message: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class UpdateMessageTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'update_message',
|
|
description: 'Update an existing message',
|
|
schema: z.object({
|
|
chatChannelId: z.string().describe('ID of the chat or channel'),
|
|
teamId: z.string().optional().describe('ID of the team (required for channel messages)'),
|
|
messageId: z.string().describe('ID of the message to update')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'PATCH',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatChannelId, teamId, messageId } = params
|
|
|
|
if (!chatChannelId || !messageId) {
|
|
throw new Error('Chat/Channel ID and Message ID are required')
|
|
}
|
|
|
|
try {
|
|
// Note: Message update is primarily for policy violations in Teams
|
|
const body = {
|
|
policyViolation: null
|
|
}
|
|
|
|
let endpoint: string
|
|
if (teamId) {
|
|
// Channel message
|
|
endpoint = `/teams/${teamId}/channels/${chatChannelId}/messages/${messageId}`
|
|
} else {
|
|
// Chat message
|
|
endpoint = `/chats/${chatChannelId}/messages/${messageId}`
|
|
}
|
|
|
|
await this.makeTeamsRequest(endpoint, 'PATCH', body)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Message updated successfully',
|
|
context: teamId ? 'channel' : 'chat'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error updating message: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class DeleteMessageTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'delete_message',
|
|
description: 'Delete a message',
|
|
schema: z.object({
|
|
chatChannelId: z.string().describe('ID of the chat or channel'),
|
|
teamId: z.string().optional().describe('ID of the team (required for channel messages)'),
|
|
messageId: z.string().describe('ID of the message to delete')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'DELETE',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatChannelId, teamId, messageId } = params
|
|
|
|
if (!chatChannelId || !messageId) {
|
|
throw new Error('Chat/Channel ID and Message ID are required')
|
|
}
|
|
|
|
try {
|
|
let endpoint: string
|
|
if (teamId) {
|
|
// Channel message - use soft delete
|
|
endpoint = `/teams/${teamId}/channels/${chatChannelId}/messages/${messageId}/softDelete`
|
|
} else {
|
|
// Chat message - use soft delete
|
|
endpoint = `/chats/${chatChannelId}/messages/${messageId}/softDelete`
|
|
}
|
|
|
|
await this.makeTeamsRequest(endpoint, 'POST', {})
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: 'Message deleted successfully',
|
|
context: teamId ? 'channel' : 'chat'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error deleting message: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class ReplyToMessageTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'reply_to_message',
|
|
description: 'Reply to a message in a chat or channel',
|
|
schema: z.object({
|
|
chatChannelId: z.string().describe('ID of the chat or channel'),
|
|
teamId: z.string().optional().describe('ID of the team (required for channel messages)'),
|
|
messageId: z.string().describe('ID of the message to reply to'),
|
|
replyBody: z.string().describe('Content of the reply'),
|
|
contentType: z.enum(['text', 'html']).optional().default('text').describe('Content type of the reply')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'POST',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatChannelId, teamId, messageId, replyBody, contentType = 'text' } = params
|
|
|
|
if (!chatChannelId || !messageId || !replyBody) {
|
|
throw new Error('Chat/Channel ID, Message ID, and Reply Body are required')
|
|
}
|
|
|
|
try {
|
|
const body = {
|
|
body: {
|
|
contentType,
|
|
content: replyBody
|
|
}
|
|
}
|
|
|
|
let endpoint: string
|
|
if (teamId) {
|
|
// Channel message reply
|
|
endpoint = `/teams/${teamId}/channels/${chatChannelId}/messages/${messageId}/replies`
|
|
} else {
|
|
// For chat messages, replies are just new messages
|
|
endpoint = `/chats/${chatChannelId}/messages`
|
|
}
|
|
|
|
const result = await this.makeTeamsRequest(endpoint, 'POST', body)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
reply: result,
|
|
message: 'Reply sent successfully',
|
|
context: teamId ? 'channel' : 'chat'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error replying to message: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class SetReactionTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'set_reaction',
|
|
description: 'Set a reaction to a message',
|
|
schema: z.object({
|
|
chatChannelId: z.string().describe('ID of the chat or channel'),
|
|
teamId: z.string().optional().describe('ID of the team (required for channel messages)'),
|
|
messageId: z.string().describe('ID of the message to react to'),
|
|
reactionType: z
|
|
.enum(['like', 'heart', 'laugh', 'surprised', 'sad', 'angry'])
|
|
.optional()
|
|
.default('like')
|
|
.describe('Type of reaction to set')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'POST',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatChannelId, teamId, messageId, reactionType = 'like' } = params
|
|
|
|
if (!chatChannelId || !messageId) {
|
|
throw new Error('Chat/Channel ID and Message ID are required')
|
|
}
|
|
|
|
try {
|
|
let endpoint: string
|
|
if (teamId) {
|
|
// Channel message
|
|
endpoint = `/teams/${teamId}/channels/${chatChannelId}/messages/${messageId}/setReaction`
|
|
} else {
|
|
// Chat message
|
|
endpoint = `/chats/${chatChannelId}/messages/${messageId}/setReaction`
|
|
}
|
|
|
|
const body = {
|
|
reactionType
|
|
}
|
|
|
|
await this.makeTeamsRequest(endpoint, 'POST', body)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: `Reaction "${reactionType}" set successfully`,
|
|
context: teamId ? 'channel' : 'chat'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error setting reaction: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class UnsetReactionTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'unset_reaction',
|
|
description: 'Remove a reaction from a message',
|
|
schema: z.object({
|
|
chatChannelId: z.string().describe('ID of the chat or channel'),
|
|
teamId: z.string().optional().describe('ID of the team (required for channel messages)'),
|
|
messageId: z.string().describe('ID of the message to remove reaction from'),
|
|
reactionType: z
|
|
.enum(['like', 'heart', 'laugh', 'surprised', 'sad', 'angry'])
|
|
.optional()
|
|
.default('like')
|
|
.describe('Type of reaction to remove')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'POST',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { chatChannelId, teamId, messageId, reactionType = 'like' } = params
|
|
|
|
if (!chatChannelId || !messageId) {
|
|
throw new Error('Chat/Channel ID and Message ID are required')
|
|
}
|
|
|
|
try {
|
|
let endpoint: string
|
|
if (teamId) {
|
|
// Channel message
|
|
endpoint = `/teams/${teamId}/channels/${chatChannelId}/messages/${messageId}/unsetReaction`
|
|
} else {
|
|
// Chat message
|
|
endpoint = `/chats/${chatChannelId}/messages/${messageId}/unsetReaction`
|
|
}
|
|
|
|
const body = {
|
|
reactionType
|
|
}
|
|
|
|
await this.makeTeamsRequest(endpoint, 'POST', body)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
message: `Reaction "${reactionType}" removed successfully`,
|
|
context: teamId ? 'channel' : 'chat'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error unsetting reaction: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
class GetAllMessagesTool extends BaseTeamsTool {
|
|
constructor(args: { accessToken?: string; defaultParams?: any }) {
|
|
const toolInput: DynamicStructuredToolInput<any> = {
|
|
name: 'get_all_messages',
|
|
description: 'Get messages across all chats and channels for the user',
|
|
schema: z.object({
|
|
maxResults: z.number().optional().default(50).describe('Maximum number of messages to return')
|
|
}),
|
|
baseUrl: BASE_URL,
|
|
method: 'GET',
|
|
headers: {}
|
|
}
|
|
|
|
super({ ...toolInput, accessToken: args.accessToken, defaultParams: args.defaultParams })
|
|
}
|
|
|
|
protected async _call(arg: any): Promise<string> {
|
|
const params = { ...arg, ...this.defaultParams }
|
|
const { maxResults = 50 } = params
|
|
|
|
try {
|
|
// Get messages from all chats
|
|
const chatEndpoint = `/me/chats/getAllMessages?$top=${maxResults}`
|
|
const chatResult = await this.makeTeamsRequest(chatEndpoint)
|
|
|
|
return this.formatResponse(
|
|
{
|
|
success: true,
|
|
messages: chatResult.value || [],
|
|
count: chatResult.value?.length || 0,
|
|
source: 'all_chats_and_channels'
|
|
},
|
|
params
|
|
)
|
|
} catch (error) {
|
|
return this.formatResponse(`Error getting all messages: ${error}`, params)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Main function to create Teams tools
|
|
export function createTeamsTools(options: TeamsToolOptions): DynamicStructuredTool[] {
|
|
const tools: DynamicStructuredTool[] = []
|
|
const actions = options.actions || []
|
|
const accessToken = options.accessToken || ''
|
|
const defaultParams = options.defaultParams || {}
|
|
|
|
// Channel tools
|
|
if (actions.includes('listChannels')) {
|
|
const listTool = new ListChannelsTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.listChannels
|
|
})
|
|
tools.push(listTool)
|
|
}
|
|
|
|
if (actions.includes('getChannel')) {
|
|
const getTool = new GetChannelTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.getChannel
|
|
})
|
|
tools.push(getTool)
|
|
}
|
|
|
|
if (actions.includes('createChannel')) {
|
|
const createTool = new CreateChannelTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.createChannel
|
|
})
|
|
tools.push(createTool)
|
|
}
|
|
|
|
if (actions.includes('updateChannel')) {
|
|
const updateTool = new UpdateChannelTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.updateChannel
|
|
})
|
|
tools.push(updateTool)
|
|
}
|
|
|
|
if (actions.includes('deleteChannel')) {
|
|
const deleteTool = new DeleteChannelTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.deleteChannel
|
|
})
|
|
tools.push(deleteTool)
|
|
}
|
|
|
|
if (actions.includes('archiveChannel')) {
|
|
const archiveTool = new ArchiveChannelTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.archiveChannel
|
|
})
|
|
tools.push(archiveTool)
|
|
}
|
|
|
|
if (actions.includes('unarchiveChannel')) {
|
|
const unarchiveTool = new UnarchiveChannelTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.unarchiveChannel
|
|
})
|
|
tools.push(unarchiveTool)
|
|
}
|
|
|
|
if (actions.includes('listChannelMembers')) {
|
|
const listMembersTool = new ListChannelMembersTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.listChannelMembers
|
|
})
|
|
tools.push(listMembersTool)
|
|
}
|
|
|
|
if (actions.includes('addChannelMember')) {
|
|
const addMemberTool = new AddChannelMemberTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.addChannelMember
|
|
})
|
|
tools.push(addMemberTool)
|
|
}
|
|
|
|
if (actions.includes('removeChannelMember')) {
|
|
const removeMemberTool = new RemoveChannelMemberTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.removeChannelMember
|
|
})
|
|
tools.push(removeMemberTool)
|
|
}
|
|
|
|
// Chat tools
|
|
if (actions.includes('listChats')) {
|
|
const listTool = new ListChatsTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.listChats
|
|
})
|
|
tools.push(listTool)
|
|
}
|
|
|
|
if (actions.includes('getChat')) {
|
|
const getTool = new GetChatTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.getChat
|
|
})
|
|
tools.push(getTool)
|
|
}
|
|
|
|
if (actions.includes('createChat')) {
|
|
const createTool = new CreateChatTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.createChat
|
|
})
|
|
tools.push(createTool)
|
|
}
|
|
|
|
if (actions.includes('updateChat')) {
|
|
const updateTool = new UpdateChatTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.updateChat
|
|
})
|
|
tools.push(updateTool)
|
|
}
|
|
|
|
if (actions.includes('deleteChat')) {
|
|
const deleteTool = new DeleteChatTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.deleteChat
|
|
})
|
|
tools.push(deleteTool)
|
|
}
|
|
|
|
if (actions.includes('listChatMembers')) {
|
|
const listMembersTool = new ListChatMembersTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.listChatMembers
|
|
})
|
|
tools.push(listMembersTool)
|
|
}
|
|
|
|
if (actions.includes('addChatMember')) {
|
|
const addMemberTool = new AddChatMemberTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.addChatMember
|
|
})
|
|
tools.push(addMemberTool)
|
|
}
|
|
|
|
if (actions.includes('removeChatMember')) {
|
|
const removeMemberTool = new RemoveChatMemberTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.removeChatMember
|
|
})
|
|
tools.push(removeMemberTool)
|
|
}
|
|
|
|
if (actions.includes('pinMessage')) {
|
|
const pinTool = new PinMessageTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.pinMessage
|
|
})
|
|
tools.push(pinTool)
|
|
}
|
|
|
|
if (actions.includes('unpinMessage')) {
|
|
const unpinTool = new UnpinMessageTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.unpinMessage
|
|
})
|
|
tools.push(unpinTool)
|
|
}
|
|
|
|
// Chat message tools
|
|
if (actions.includes('listMessages')) {
|
|
const listTool = new ListMessagesTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.listMessages
|
|
})
|
|
tools.push(listTool)
|
|
}
|
|
|
|
if (actions.includes('getMessage')) {
|
|
const getTool = new GetMessageTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.getMessage
|
|
})
|
|
tools.push(getTool)
|
|
}
|
|
|
|
if (actions.includes('sendMessage')) {
|
|
const sendTool = new SendMessageTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.sendMessage
|
|
})
|
|
tools.push(sendTool)
|
|
}
|
|
|
|
if (actions.includes('updateMessage')) {
|
|
const updateTool = new UpdateMessageTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.updateMessage
|
|
})
|
|
tools.push(updateTool)
|
|
}
|
|
|
|
if (actions.includes('deleteMessage')) {
|
|
const deleteTool = new DeleteMessageTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.deleteMessage
|
|
})
|
|
tools.push(deleteTool)
|
|
}
|
|
|
|
if (actions.includes('replyToMessage')) {
|
|
const replyTool = new ReplyToMessageTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.replyToMessage
|
|
})
|
|
tools.push(replyTool)
|
|
}
|
|
|
|
if (actions.includes('setReaction')) {
|
|
const reactionTool = new SetReactionTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.setReaction
|
|
})
|
|
tools.push(reactionTool)
|
|
}
|
|
|
|
if (actions.includes('unsetReaction')) {
|
|
const unsetReactionTool = new UnsetReactionTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.unsetReaction
|
|
})
|
|
tools.push(unsetReactionTool)
|
|
}
|
|
|
|
if (actions.includes('getAllMessages')) {
|
|
const getAllTool = new GetAllMessagesTool({
|
|
accessToken,
|
|
defaultParams: defaultParams.getAllMessages
|
|
})
|
|
tools.push(getAllTool)
|
|
}
|
|
|
|
return tools
|
|
}
|