mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
improvement: added gmail draft operation
This commit is contained in:
@@ -14,17 +14,17 @@ export const GmailBlock: BlockConfig<GmailToolResponse> = {
|
||||
icon: GmailIcon,
|
||||
subBlocks: [
|
||||
// Operation selector
|
||||
// {
|
||||
// id: 'operation',
|
||||
// title: 'Operation',
|
||||
// type: 'dropdown',
|
||||
// layout: 'full',
|
||||
// options: [
|
||||
// { label: 'Send Email', id: 'send_gmail' },
|
||||
// // { label: 'Read Email', id: 'read_gmail' },
|
||||
// // { label: 'Search Emails', id: 'search_gmail' },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
layout: 'full',
|
||||
options: [
|
||||
{ label: 'Send Email', id: 'send_gmail' },
|
||||
// { label: 'Read Email', id: 'read_gmail' },
|
||||
{ label: 'Draft Email', id: 'draft_gmail' },
|
||||
],
|
||||
},
|
||||
// Gmail Credentials
|
||||
{
|
||||
id: 'credential',
|
||||
@@ -48,7 +48,7 @@ export const GmailBlock: BlockConfig<GmailToolResponse> = {
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Recipient email address',
|
||||
// condition: { field: 'operation', value: 'send_gmail' },
|
||||
condition: { field: 'operation', value: ['send_gmail', 'draft_gmail'] },
|
||||
},
|
||||
{
|
||||
id: 'subject',
|
||||
@@ -56,7 +56,7 @@ export const GmailBlock: BlockConfig<GmailToolResponse> = {
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Email subject',
|
||||
// condition: { field: 'operation', value: 'send_gmail' },
|
||||
condition: { field: 'operation', value: ['send_gmail', 'draft_gmail'] },
|
||||
},
|
||||
{
|
||||
id: 'body',
|
||||
@@ -64,7 +64,7 @@ export const GmailBlock: BlockConfig<GmailToolResponse> = {
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Email content',
|
||||
// condition: { field: 'operation', value: 'send_gmail' },
|
||||
condition: { field: 'operation', value: ['send_gmail', 'draft_gmail'] },
|
||||
},
|
||||
// Read Email Fields - Add folder selector
|
||||
// {
|
||||
@@ -130,22 +130,17 @@ export const GmailBlock: BlockConfig<GmailToolResponse> = {
|
||||
// },
|
||||
],
|
||||
tools: {
|
||||
access: ['gmail_send', 'gmail_read', 'gmail_search'],
|
||||
access: ['gmail_send', 'gmail_draft'],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
// Since we only have send_gmail now, we can simplify this
|
||||
return 'gmail_send'
|
||||
|
||||
// switch (params.operation) {
|
||||
// case 'send_gmail':
|
||||
// return 'gmail_send'
|
||||
// case 'read_gmail':
|
||||
// return 'gmail_read'
|
||||
// case 'search_gmail':
|
||||
// return 'gmail_search'
|
||||
// default:
|
||||
// throw new Error(`Invalid Gmail operation: ${params.operation}`)
|
||||
// }
|
||||
switch (params.operation) {
|
||||
case 'send_gmail':
|
||||
return 'gmail_send'
|
||||
case 'draft_gmail':
|
||||
return 'gmail_draft'
|
||||
default:
|
||||
throw new Error(`Invalid Gmail operation: ${params.operation}`)
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
// Pass the credential directly from the credential field
|
||||
@@ -158,13 +153,13 @@ export const GmailBlock: BlockConfig<GmailToolResponse> = {
|
||||
|
||||
return {
|
||||
...rest,
|
||||
credential, // Keep the credential parameter
|
||||
credential,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
// operation: { type: 'string', required: true },
|
||||
operation: { type: 'string', required: true },
|
||||
credential: { type: 'string', required: true },
|
||||
// Send operation inputs
|
||||
to: { type: 'string', required: false },
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
import type { ToolConfig } from '../types'
|
||||
import type { GmailSendParams, GmailToolResponse } from './types'
|
||||
|
||||
const GMAIL_API_BASE = 'https://gmail.googleapis.com/gmail/v1/users/me'
|
||||
|
||||
export const gmailDraftTool: ToolConfig<GmailSendParams, GmailToolResponse> = {
|
||||
id: 'gmail_draft',
|
||||
name: 'Gmail Draft',
|
||||
description: 'Draft emails using Gmail',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-email',
|
||||
additionalScopes: ['https://www.googleapis.com/auth/gmail.compose'],
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Access token for Gmail API',
|
||||
},
|
||||
to: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Recipient email address',
|
||||
},
|
||||
subject: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Email subject',
|
||||
},
|
||||
body: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Email body content',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: () => `${GMAIL_API_BASE}/drafts`,
|
||||
method: 'POST',
|
||||
headers: (params: GmailSendParams) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: GmailSendParams): Record<string, any> => {
|
||||
const email = [
|
||||
'Content-Type: text/plain; charset="UTF-8"',
|
||||
'MIME-Version: 1.0',
|
||||
`To: ${params.to}`,
|
||||
`Subject: ${params.subject}`,
|
||||
'',
|
||||
params.body,
|
||||
].join('\n')
|
||||
|
||||
return {
|
||||
message: {
|
||||
raw: Buffer.from(email).toString('base64url'),
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to draft email')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content: 'Email drafted successfully',
|
||||
metadata: {
|
||||
id: data.id,
|
||||
message: {
|
||||
id: data.message?.id,
|
||||
threadId: data.message?.threadId,
|
||||
labelIds: data.message?.labelIds,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error) => {
|
||||
if (error.error?.message) {
|
||||
if (error.error.message.includes('invalid authentication credentials')) {
|
||||
return 'Invalid or expired access token. Please reauthenticate.'
|
||||
}
|
||||
if (error.error.message.includes('quota')) {
|
||||
return 'Gmail API quota exceeded. Please try again later.'
|
||||
}
|
||||
return error.error.message
|
||||
}
|
||||
return error.message || 'An unexpected error occurred while drafting email'
|
||||
},
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { gmailDraftTool } from './draft'
|
||||
import { gmailReadTool } from './read'
|
||||
import { gmailSearchTool } from './search'
|
||||
import { gmailSendTool } from './send'
|
||||
|
||||
export { gmailSendTool, gmailReadTool, gmailSearchTool }
|
||||
export { gmailSendTool, gmailReadTool, gmailSearchTool, gmailDraftTool }
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
githubPrTool,
|
||||
githubRepoInfoTool,
|
||||
} from './github'
|
||||
import { gmailReadTool, gmailSearchTool, gmailSendTool } from './gmail'
|
||||
import { gmailDraftTool, gmailReadTool, gmailSearchTool, gmailSendTool } from './gmail'
|
||||
import { searchTool as googleSearchTool } from './google'
|
||||
import {
|
||||
googleCalendarCreateTool,
|
||||
@@ -142,6 +142,7 @@ export const tools: Record<string, ToolConfig> = {
|
||||
gmail_send: gmailSendTool,
|
||||
gmail_read: gmailReadTool,
|
||||
gmail_search: gmailSearchTool,
|
||||
gmail_draft: gmailDraftTool,
|
||||
whatsapp_send_message: whatsappSendMessageTool,
|
||||
x_write: xWriteTool,
|
||||
x_read: xReadTool,
|
||||
|
||||
Reference in New Issue
Block a user