Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions apps/docs/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1302,6 +1302,37 @@ export function GoogleCalendarIcon(props: SVGProps<SVGSVGElement>) {
)
}

export function GoogleChatIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 311 320' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path
fill='#0066da'
d='M76.37 0.51L76.38 76.98L0 76.96L0 20.77Q0.85 14.81 3.53 10.76Q10.14 0.74 22.75 0.67Q49.41 0.53 76.37 0.51Z'
/>
<path
fill='#fbbc04'
d='M76.37 0.51L233.79 0.53A1.61 1.57-26.7 0 1 234.71 0.82L235.08 1.09Q234.92 1.15 234.81 1.22Q234.64 1.31 234.64 1.5L234.62 77.01Q234.6 77.01 234.57 77.01L76.41 77.01Q76.4 77 76.38 76.98L76.37 0.51Z'
/>
<path
fill='#ea4335'
d='M235.08 1.09L310.53 76.77L234.62 77.01L234.64 1.5Q234.64 1.31 234.81 1.22Q234.92 1.15 235.08 1.09Z'
/>
<path
fill='#2684fc'
d='M0 76.96L76.38 76.98Q76.4 77 76.41 77.01L76.43 182.69L0 182.67L0 76.96Z'
/>
<path
fill='#00ac47'
d='M310.53 76.77L311 77.11L311 239.01Q308.34 253.54 295.94 257.78Q291.52 259.3 282.91 259.28Q227.02 259.19 169.99 259.11Q161.71 259.1 153.19 259.23Q152.72 259.24 152.39 259.57Q124.49 287.34 96.39 315.59C93.52 318.48 90.27 320.09 86.15 319.48Q80.39 318.63 77.66 313.54Q76.51 311.38 76.49 305.66Q76.42 282.47 76.44 259.13L76.43 220.85L114.21 183.07A1.79 1.77 22.3 0 1 115.47 182.55L233.77 182.59A0.83 0.83 0 0 0 234.6 181.76L234.57 77.01Q234.6 77.01 234.62 77.01L310.53 76.77Z'
/>
<path
fill='#00832d'
d='M76.43 182.69L76.43 220.85L76.44 259.13Q52.47 259.27 28.91 259.22Q19.09 259.2 14.76 257.68Q2.62 253.44 0 238.88L0 182.67L76.43 182.69Z'
/>
</svg>
)
}

export function SupabaseIcon(props: SVGProps<SVGSVGElement>) {
const id = useId()
const gradient0 = `supabase_paint0_${id}`
Expand Down
2 changes: 2 additions & 0 deletions apps/docs/components/ui/icon-mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
GongIcon,
GoogleBooksIcon,
GoogleCalendarIcon,
GoogleChatIcon,
GoogleDocsIcon,
GoogleDriveIcon,
GoogleFormsIcon,
Expand Down Expand Up @@ -189,6 +190,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
gong: GongIcon,
google_books: GoogleBooksIcon,
google_calendar_v2: GoogleCalendarIcon,
google_chat: GoogleChatIcon,
google_docs: GoogleDocsIcon,
google_drive: GoogleDriveIcon,
google_forms: GoogleFormsIcon,
Expand Down
62 changes: 62 additions & 0 deletions apps/docs/content/docs/en/tools/google_chat.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
title: Google Chat
description: Send messages and manage Google Chat spaces
---

import { BlockInfoCard } from "@/components/ui/block-info-card"

<BlockInfoCard
type="google_chat"
color="#E0E0E0"
/>

## Usage Instructions

Integrate with Google Chat to send messages to spaces and list available spaces using OAuth.



## Tools

### `google_chat_send_message`

Send a message to a Google Chat space

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `spaceId` | string | Yes | The Google Chat space ID \(e.g., spaces/AAAA1234\) |
| `message` | string | Yes | Message text to send |
| `threadKey` | string | No | Thread key for sending a threaded reply |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `messageName` | string | Google Chat message resource name |
| `spaceName` | string | Space the message was sent to |
| `threadName` | string | Thread resource name |
| `text` | string | Message text that was sent |
| `createTime` | string | Timestamp when the message was created |

### `google_chat_list_spaces`

List Google Chat spaces the user is a member of

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `pageSize` | number | No | Maximum number of spaces to return \(default 100, max 1000\) |
| `pageToken` | string | No | Token for fetching the next page of results |
| `filter` | string | No | Filter by space type \(e.g., spaceType = "SPACE", spaceType = "GROUP_CHAT" OR spaceType = "DIRECT_MESSAGE"\) |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `spaces` | json | Array of Google Chat space objects |
| `nextPageToken` | string | Token for fetching the next page of results |


1 change: 1 addition & 0 deletions apps/docs/content/docs/en/tools/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"gong",
"google_books",
"google_calendar",
"google_chat",
"google_docs",
"google_drive",
"google_forms",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const SCOPE_DESCRIPTIONS: Record<string, string> = {
'https://www.googleapis.com/auth/admin.directory.group.readonly': 'View Google Workspace groups',
'https://www.googleapis.com/auth/admin.directory.group.member.readonly':
'View Google Workspace group memberships',
'https://www.googleapis.com/auth/chat.spaces.readonly': 'View Google Chat spaces',
'https://www.googleapis.com/auth/chat.messages.create': 'Send messages in Google Chat',
'https://www.googleapis.com/auth/cloud-platform':
'Full access to Google Cloud resources for Vertex AI',
'read:confluence-content.all': 'Read all Confluence content',
Expand Down
143 changes: 143 additions & 0 deletions apps/sim/blocks/blocks/google_chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { GoogleChatIcon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import { AuthMode } from '@/blocks/types'
import type { GoogleChatResponse } from '@/tools/google_chat/types'

export const GoogleChatBlock: BlockConfig<GoogleChatResponse> = {
type: 'google_chat',
name: 'Google Chat',
description: 'Send messages and manage Google Chat spaces',
authMode: AuthMode.OAuth,
longDescription:
'Integrate with Google Chat to send messages to spaces and list available spaces using OAuth.',
docsLink: 'https://docs.sim.ai/tools/google_chat',
category: 'tools',
bgColor: '#E0E0E0',
icon: GoogleChatIcon,
subBlocks: [
{
id: 'operation',
title: 'Operation',
type: 'dropdown',
options: [
{ label: 'Send Message', id: 'send_message' },
{ label: 'List Spaces', id: 'list_spaces' },
],
value: () => 'send_message',
},
{
id: 'credential',
title: 'Google Chat Account',
type: 'oauth-input',
canonicalParamId: 'oauthCredential',
mode: 'basic',
required: true,
serviceId: 'google-chat',
requiredScopes: [
'https://www.googleapis.com/auth/chat.spaces.readonly',
'https://www.googleapis.com/auth/chat.messages.create',
],
placeholder: 'Select Google account',
},
{
id: 'manualCredential',
title: 'Google Chat Account',
type: 'short-input',
canonicalParamId: 'oauthCredential',
mode: 'advanced',
placeholder: 'Enter credential ID',
required: true,
},
{
id: 'spaceId',
title: 'Space ID',
type: 'short-input',
placeholder: 'e.g., spaces/AAAA1234 or AAAA1234',
required: { field: 'operation', value: 'send_message' },
condition: { field: 'operation', value: 'send_message' },
},
{
id: 'message',
title: 'Message',
type: 'long-input',
placeholder: 'Enter your message',
required: { field: 'operation', value: 'send_message' },
condition: { field: 'operation', value: 'send_message' },
},
{
id: 'threadKey',
title: 'Thread Key',
type: 'short-input',
placeholder: 'Optional thread key for threaded replies',
condition: { field: 'operation', value: 'send_message' },
},
{
id: 'filter',
title: 'Filter',
type: 'short-input',
placeholder: 'e.g., spaceType = "SPACE"',
condition: { field: 'operation', value: 'list_spaces' },
},
{
id: 'pageSize',
title: 'Max Results',
type: 'short-input',
placeholder: 'Maximum spaces to return (default 100)',
condition: { field: 'operation', value: 'list_spaces' },
},
],
tools: {
access: ['google_chat_send_message', 'google_chat_list_spaces'],
config: {
tool: (params) => {
switch (params.operation) {
case 'send_message':
return 'google_chat_send_message'
case 'list_spaces':
return 'google_chat_list_spaces'
default:
throw new Error(`Invalid Google Chat operation: ${params.operation}`)
}
},
params: (params) => {
const { oauthCredential, operation, ...rest } = params

switch (operation) {
case 'send_message':
return {
oauthCredential,
spaceId: rest.spaceId,
message: rest.message,
threadKey: rest.threadKey,
}
case 'list_spaces':
return {
oauthCredential,
pageSize: rest.pageSize ? Number(rest.pageSize) : undefined,
filter: rest.filter,
}
default:
return { oauthCredential, ...rest }
}
},
},
},
inputs: {
operation: { type: 'string', description: 'Operation to perform' },
oauthCredential: { type: 'string', description: 'Google Chat OAuth credential' },
spaceId: { type: 'string', description: 'Google Chat space ID' },
message: { type: 'string', description: 'Message text to send' },
threadKey: { type: 'string', description: 'Thread key for threaded replies' },
filter: { type: 'string', description: 'Filter by space type' },
pageSize: { type: 'number', description: 'Maximum number of spaces to return' },
},
outputs: {
messageName: { type: 'string', description: 'Message resource name' },
spaceName: { type: 'string', description: 'Space resource name' },
threadName: { type: 'string', description: 'Thread resource name' },
text: { type: 'string', description: 'Message text that was sent' },
createTime: { type: 'string', description: 'Message creation timestamp' },
spaces: { type: 'json', description: 'Array of Google Chat space objects' },
nextPageToken: { type: 'string', description: 'Token for next page of results' },
},
}
2 changes: 2 additions & 0 deletions apps/sim/blocks/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { GongBlock } from '@/blocks/blocks/gong'
import { GoogleSearchBlock } from '@/blocks/blocks/google'
import { GoogleBooksBlock } from '@/blocks/blocks/google_books'
import { GoogleCalendarBlock, GoogleCalendarV2Block } from '@/blocks/blocks/google_calendar'
import { GoogleChatBlock } from '@/blocks/blocks/google_chat'
import { GoogleDocsBlock } from '@/blocks/blocks/google_docs'
import { GoogleDriveBlock } from '@/blocks/blocks/google_drive'
import { GoogleFormsBlock } from '@/blocks/blocks/google_forms'
Expand Down Expand Up @@ -227,6 +228,7 @@ export const registry: Record<string, BlockConfig> = {
gmail: GmailBlock,
gmail_v2: GmailV2Block,
google_calendar: GoogleCalendarBlock,
google_chat: GoogleChatBlock,
google_calendar_v2: GoogleCalendarV2Block,
google_books: GoogleBooksBlock,
google_docs: GoogleDocsBlock,
Expand Down
31 changes: 31 additions & 0 deletions apps/sim/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1302,6 +1302,37 @@ export function GoogleCalendarIcon(props: SVGProps<SVGSVGElement>) {
)
}

export function GoogleChatIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 311 320' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path
fill='#0066da'
d='M76.37 0.51L76.38 76.98L0 76.96L0 20.77Q0.85 14.81 3.53 10.76Q10.14 0.74 22.75 0.67Q49.41 0.53 76.37 0.51Z'
/>
<path
fill='#fbbc04'
d='M76.37 0.51L233.79 0.53A1.61 1.57-26.7 0 1 234.71 0.82L235.08 1.09Q234.92 1.15 234.81 1.22Q234.64 1.31 234.64 1.5L234.62 77.01Q234.6 77.01 234.57 77.01L76.41 77.01Q76.4 77 76.38 76.98L76.37 0.51Z'
/>
<path
fill='#ea4335'
d='M235.08 1.09L310.53 76.77L234.62 77.01L234.64 1.5Q234.64 1.31 234.81 1.22Q234.92 1.15 235.08 1.09Z'
/>
<path
fill='#2684fc'
d='M0 76.96L76.38 76.98Q76.4 77 76.41 77.01L76.43 182.69L0 182.67L0 76.96Z'
/>
<path
fill='#00ac47'
d='M310.53 76.77L311 77.11L311 239.01Q308.34 253.54 295.94 257.78Q291.52 259.3 282.91 259.28Q227.02 259.19 169.99 259.11Q161.71 259.1 153.19 259.23Q152.72 259.24 152.39 259.57Q124.49 287.34 96.39 315.59C93.52 318.48 90.27 320.09 86.15 319.48Q80.39 318.63 77.66 313.54Q76.51 311.38 76.49 305.66Q76.42 282.47 76.44 259.13L76.43 220.85L114.21 183.07A1.79 1.77 22.3 0 1 115.47 182.55L233.77 182.59A0.83 0.83 0 0 0 234.6 181.76L234.57 77.01Q234.6 77.01 234.62 77.01L310.53 76.77Z'
/>
<path
fill='#00832d'
d='M76.43 182.69L76.43 220.85L76.44 259.13Q52.47 259.27 28.91 259.22Q19.09 259.2 14.76 257.68Q2.62 253.44 0 238.88L0 182.67L76.43 182.69Z'
/>
</svg>
)
}

export function SupabaseIcon(props: SVGProps<SVGSVGElement>) {
const id = useId()
const gradient0 = `supabase_paint0_${id}`
Expand Down
42 changes: 42 additions & 0 deletions apps/sim/lib/auth/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ export const auth = betterAuth({
'google-forms',
'google-vault',
'google-groups',
'google-chat',
'vertex-ai',
'github-repo',
'microsoft-dataverse',
Expand Down Expand Up @@ -1150,6 +1151,47 @@ export const auth = betterAuth({
},
},

{
providerId: 'google-chat',
clientId: env.GOOGLE_CLIENT_ID as string,
clientSecret: env.GOOGLE_CLIENT_SECRET as string,
discoveryUrl: 'https://accounts.google.com/.well-known/openid-configuration',
accessType: 'offline',
scopes: [
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/chat.spaces.readonly',
'https://www.googleapis.com/auth/chat.messages.create',
],
prompt: 'consent',
redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/google-chat`,
getUserInfo: async (tokens) => {
try {
const response = await fetch('https://openidconnect.googleapis.com/v1/userinfo', {
headers: { Authorization: `Bearer ${tokens.accessToken}` },
})
if (!response.ok) {
logger.error('Failed to fetch Google user info', { status: response.status })
throw new Error(`Failed to fetch Google user info: ${response.statusText}`)
}
const profile = await response.json()
const now = new Date()
return {
id: `${profile.sub}-${crypto.randomUUID()}`,
name: profile.name || 'Google User',
email: profile.email,
image: profile.picture || undefined,
emailVerified: profile.email_verified || false,
createdAt: now,
updatedAt: now,
}
} catch (error) {
logger.error('Error in Google getUserInfo', { error })
throw error
}
},
},

{
providerId: 'vertex-ai',
clientId: env.GOOGLE_CLIENT_ID as string,
Expand Down
Loading