From 3d56ac9bb69073d983a6578b8c91129130ab5cb5 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 25 Feb 2026 12:06:23 -0800 Subject: [PATCH 1/4] feat(google-chat): add Google Chat integration with OAuth --- apps/docs/components/icons.tsx | 36 +++++ apps/docs/components/ui/icon-mapping.ts | 14 +- .../content/docs/en/tools/google_chat.mdx | 62 ++++++++ apps/docs/content/docs/en/tools/meta.json | 3 +- .../components/oauth-required-modal.tsx | 2 + apps/sim/blocks/blocks/google_chat.ts | 143 ++++++++++++++++++ apps/sim/blocks/registry.ts | 2 + apps/sim/components/icons.tsx | 36 +++++ apps/sim/lib/oauth/oauth.ts | 12 ++ apps/sim/lib/oauth/types.ts | 2 + apps/sim/tools/google_chat/index.ts | 5 + apps/sim/tools/google_chat/list_spaces.ts | 89 +++++++++++ apps/sim/tools/google_chat/send_message.ts | 98 ++++++++++++ apps/sim/tools/google_chat/types.ts | 33 ++++ apps/sim/tools/registry.ts | 3 + 15 files changed, 533 insertions(+), 7 deletions(-) create mode 100644 apps/docs/content/docs/en/tools/google_chat.mdx create mode 100644 apps/sim/blocks/blocks/google_chat.ts create mode 100644 apps/sim/tools/google_chat/index.ts create mode 100644 apps/sim/tools/google_chat/list_spaces.ts create mode 100644 apps/sim/tools/google_chat/send_message.ts create mode 100644 apps/sim/tools/google_chat/types.ts diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index dcd5741f2b..58f5ef6cba 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -1302,6 +1302,42 @@ export function GoogleCalendarIcon(props: SVGProps) { ) } +export function GoogleChatIcon(props: SVGProps) { + return ( + + + + + + + + + ) +} + export function SupabaseIcon(props: SVGProps) { const id = useId() const gradient0 = `supabase_paint0_${id}` diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index 5121253240..407d6bd578 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -38,12 +38,13 @@ import { EyeIcon, FirecrawlIcon, FirefliesIcon, - GithubIcon, GitLabIcon, + GithubIcon, GmailIcon, GongIcon, GoogleBooksIcon, GoogleCalendarIcon, + GoogleChatIcon, GoogleDocsIcon, GoogleDriveIcon, GoogleFormsIcon, @@ -72,9 +73,9 @@ import { LinearIcon, LinkedInIcon, LinkupIcon, + MailServerIcon, MailchimpIcon, MailgunIcon, - MailServerIcon, Mem0Icon, MicrosoftDataverseIcon, MicrosoftExcelIcon, @@ -107,6 +108,8 @@ import { ResendIcon, RevenueCatIcon, S3Icon, + SQSIcon, + STTIcon, SalesforceIcon, SearchIcon, SendgridIcon, @@ -118,19 +121,17 @@ import { SimilarwebIcon, SlackIcon, SmtpIcon, - SQSIcon, SshIcon, - STTIcon, StagehandIcon, StripeIcon, SupabaseIcon, + TTSIcon, TavilyIcon, TelegramIcon, TextractIcon, TinybirdIcon, TranslateIcon, TrelloIcon, - TTSIcon, TwilioIcon, TypeformIcon, UpstashIcon, @@ -141,11 +142,11 @@ import { WhatsAppIcon, WikipediaIcon, WordpressIcon, - xIcon, YouTubeIcon, ZendeskIcon, ZepIcon, ZoomIcon, + xIcon, } from '@/components/icons' type IconComponent = ComponentType> @@ -189,6 +190,7 @@ export const blockTypeToIconMap: Record = { gong: GongIcon, google_books: GoogleBooksIcon, google_calendar_v2: GoogleCalendarIcon, + google_chat: GoogleChatIcon, google_docs: GoogleDocsIcon, google_drive: GoogleDriveIcon, google_forms: GoogleFormsIcon, diff --git a/apps/docs/content/docs/en/tools/google_chat.mdx b/apps/docs/content/docs/en/tools/google_chat.mdx new file mode 100644 index 0000000000..ed9c49ab07 --- /dev/null +++ b/apps/docs/content/docs/en/tools/google_chat.mdx @@ -0,0 +1,62 @@ +--- +title: Google Chat +description: Send messages and manage Google Chat spaces +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## 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 | + + diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index 9fc1cc577e..8fb3410b68 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -39,6 +39,7 @@ "gong", "google_books", "google_calendar", + "google_chat", "google_docs", "google_drive", "google_forms", @@ -146,4 +147,4 @@ "zep", "zoom" ] -} +} \ No newline at end of file diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal.tsx index 6cac32e626..874fd95e8b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal.tsx @@ -52,6 +52,8 @@ const SCOPE_DESCRIPTIONS: Record = { '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', diff --git a/apps/sim/blocks/blocks/google_chat.ts b/apps/sim/blocks/blocks/google_chat.ts new file mode 100644 index 0000000000..435d5b202f --- /dev/null +++ b/apps/sim/blocks/blocks/google_chat.ts @@ -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 = { + 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' }, + }, +} diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index 03b9827a77..42a55a773d 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -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' @@ -227,6 +228,7 @@ export const registry: Record = { gmail: GmailBlock, gmail_v2: GmailV2Block, google_calendar: GoogleCalendarBlock, + google_chat: GoogleChatBlock, google_calendar_v2: GoogleCalendarV2Block, google_books: GoogleBooksBlock, google_docs: GoogleDocsBlock, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index dcd5741f2b..58f5ef6cba 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -1302,6 +1302,42 @@ export function GoogleCalendarIcon(props: SVGProps) { ) } +export function GoogleChatIcon(props: SVGProps) { + return ( + + + + + + + + + ) +} + export function SupabaseIcon(props: SVGProps) { const id = useId() const gradient0 = `supabase_paint0_${id}` diff --git a/apps/sim/lib/oauth/oauth.ts b/apps/sim/lib/oauth/oauth.ts index b890566334..158361e031 100644 --- a/apps/sim/lib/oauth/oauth.ts +++ b/apps/sim/lib/oauth/oauth.ts @@ -12,6 +12,7 @@ import { GoogleDocsIcon, GoogleDriveIcon, GoogleFormsIcon, + GoogleChatIcon, GoogleGroupsIcon, GoogleIcon, GoogleSheetsIcon, @@ -141,6 +142,17 @@ export const OAUTH_PROVIDERS: Record = { 'https://www.googleapis.com/auth/admin.directory.group.member', ], }, + 'google-chat': { + name: 'Google Chat', + description: 'Send messages and manage Google Chat spaces.', + providerId: 'google-chat', + icon: GoogleChatIcon, + baseProviderIcon: GoogleIcon, + scopes: [ + 'https://www.googleapis.com/auth/chat.spaces.readonly', + 'https://www.googleapis.com/auth/chat.messages.create', + ], + }, 'vertex-ai': { name: 'Vertex AI', description: 'Access Google Cloud Vertex AI for Gemini models with OAuth.', diff --git a/apps/sim/lib/oauth/types.ts b/apps/sim/lib/oauth/types.ts index d5114a38bc..639e88cf48 100644 --- a/apps/sim/lib/oauth/types.ts +++ b/apps/sim/lib/oauth/types.ts @@ -10,6 +10,7 @@ export type OAuthProvider = | 'google-vault' | 'google-forms' | 'google-groups' + | 'google-chat' | 'vertex-ai' | 'github' | 'github-repo' @@ -55,6 +56,7 @@ export type OAuthService = | 'google-vault' | 'google-forms' | 'google-groups' + | 'google-chat' | 'vertex-ai' | 'github' | 'x' diff --git a/apps/sim/tools/google_chat/index.ts b/apps/sim/tools/google_chat/index.ts new file mode 100644 index 0000000000..db7844b43c --- /dev/null +++ b/apps/sim/tools/google_chat/index.ts @@ -0,0 +1,5 @@ +import { listSpacesTool } from './list_spaces' +import { sendMessageTool } from './send_message' + +export const googleChatSendMessageTool = sendMessageTool +export const googleChatListSpacesTool = listSpacesTool diff --git a/apps/sim/tools/google_chat/list_spaces.ts b/apps/sim/tools/google_chat/list_spaces.ts new file mode 100644 index 0000000000..5d18268704 --- /dev/null +++ b/apps/sim/tools/google_chat/list_spaces.ts @@ -0,0 +1,89 @@ +import type { GoogleChatListSpacesParams, GoogleChatResponse } from '@/tools/google_chat/types' +import type { ToolConfig } from '@/tools/types' + +export const listSpacesTool: ToolConfig = { + id: 'google_chat_list_spaces', + name: 'Google Chat List Spaces', + description: 'List Google Chat spaces the user is a member of', + version: '1.0.0', + + oauth: { + required: true, + provider: 'google-chat', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'OAuth access token', + }, + pageSize: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of spaces to return (default 100, max 1000)', + }, + pageToken: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Token for fetching the next page of results', + }, + filter: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Filter by space type (e.g., spaceType = "SPACE", spaceType = "GROUP_CHAT" OR spaceType = "DIRECT_MESSAGE")', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://chat.googleapis.com/v1/spaces') + if (params.pageSize) { + url.searchParams.set('pageSize', String(params.pageSize)) + } + if (params.pageToken) { + url.searchParams.set('pageToken', params.pageToken) + } + if (params.filter) { + url.searchParams.set('filter', params.filter) + } + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.error?.message || 'Failed to list spaces') + } + return { + success: true, + output: { + spaces: data.spaces ?? [], + nextPageToken: data.nextPageToken ?? null, + }, + } + }, + + outputs: { + spaces: { + type: 'json', + description: 'Array of Google Chat space objects', + }, + nextPageToken: { + type: 'string', + description: 'Token for fetching the next page of results', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/google_chat/send_message.ts b/apps/sim/tools/google_chat/send_message.ts new file mode 100644 index 0000000000..e50156f316 --- /dev/null +++ b/apps/sim/tools/google_chat/send_message.ts @@ -0,0 +1,98 @@ +import type { GoogleChatResponse, GoogleChatSendMessageParams } from '@/tools/google_chat/types' +import type { ToolConfig } from '@/tools/types' + +export const sendMessageTool: ToolConfig = { + id: 'google_chat_send_message', + name: 'Google Chat Send Message', + description: 'Send a message to a Google Chat space', + version: '1.0.0', + + oauth: { + required: true, + provider: 'google-chat', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'OAuth access token', + }, + spaceId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Google Chat space ID (e.g., spaces/AAAA1234)', + }, + message: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Message text to send', + }, + threadKey: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Thread key for sending a threaded reply', + }, + }, + + request: { + url: (params) => { + const spaceId = params.spaceId?.trim() + if (!spaceId) { + throw new Error('Space ID is required') + } + const spaceName = spaceId.startsWith('spaces/') ? spaceId : `spaces/${spaceId}` + const url = new URL(`https://chat.googleapis.com/v1/${spaceName}/messages`) + if (params.threadKey) { + url.searchParams.set( + 'messageReplyOption', + 'REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD' + ) + } + return url.toString() + }, + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: Record = { + text: params.message, + } + if (params.threadKey) { + body.thread = { threadKey: params.threadKey } + } + return body + }, + }, + + transformResponse: async (response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.error?.message || 'Failed to send message') + } + return { + success: true, + output: { + messageName: data.name ?? null, + spaceName: data.space?.name ?? null, + threadName: data.thread?.name ?? null, + text: data.text ?? null, + createTime: data.createTime ?? null, + }, + } + }, + + outputs: { + messageName: { type: 'string', description: 'Google Chat message resource name' }, + spaceName: { type: 'string', description: 'Space the message was sent to' }, + threadName: { type: 'string', description: 'Thread resource name', optional: true }, + text: { type: 'string', description: 'Message text that was sent' }, + createTime: { type: 'string', description: 'Timestamp when the message was created' }, + }, +} diff --git a/apps/sim/tools/google_chat/types.ts b/apps/sim/tools/google_chat/types.ts new file mode 100644 index 0000000000..f41c339090 --- /dev/null +++ b/apps/sim/tools/google_chat/types.ts @@ -0,0 +1,33 @@ +import type { ToolResponse } from '@/tools/types' + +/** + * Common parameters for Google Chat API calls + */ +export interface GoogleChatCommonParams { + accessToken: string +} + +/** + * Parameters for sending a message to a Google Chat space + */ +export interface GoogleChatSendMessageParams extends GoogleChatCommonParams { + spaceId: string + message: string + threadKey?: string +} + +/** + * Parameters for listing Google Chat spaces + */ +export interface GoogleChatListSpacesParams extends GoogleChatCommonParams { + pageSize?: number + pageToken?: string + filter?: string +} + +/** + * Standard response for Google Chat operations + */ +export interface GoogleChatResponse extends ToolResponse { + output: Record +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 5a2f5787c7..ca7e848e7b 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -621,6 +621,7 @@ import { } from '@/tools/gong' import { googleSearchTool } from '@/tools/google' import { googleBooksVolumeDetailsTool, googleBooksVolumeSearchTool } from '@/tools/google_books' +import { googleChatListSpacesTool, googleChatSendMessageTool } from '@/tools/google_chat' import { googleCalendarCreateTool, googleCalendarCreateV2Tool, @@ -2878,6 +2879,8 @@ export const tools: Record = { google_docs_create: googleDocsCreateTool, google_books_volume_search: googleBooksVolumeSearchTool, google_books_volume_details: googleBooksVolumeDetailsTool, + google_chat_list_spaces: googleChatListSpacesTool, + google_chat_send_message: googleChatSendMessageTool, google_maps_air_quality: googleMapsAirQualityTool, google_maps_directions: googleMapsDirectionsTool, google_maps_distance_matrix: googleMapsDistanceMatrixTool, From 5cccde3301b1cda1b5a547e8d2de65232f39db1a Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 25 Feb 2026 13:05:10 -0800 Subject: [PATCH 2/4] fix(google-chat): use underscore in docsLink path --- apps/sim/blocks/blocks/google_chat.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sim/blocks/blocks/google_chat.ts b/apps/sim/blocks/blocks/google_chat.ts index 435d5b202f..b5bd75c8bf 100644 --- a/apps/sim/blocks/blocks/google_chat.ts +++ b/apps/sim/blocks/blocks/google_chat.ts @@ -10,7 +10,7 @@ export const GoogleChatBlock: BlockConfig = { 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', + docsLink: 'https://docs.sim.ai/tools/google_chat', category: 'tools', bgColor: '#E0E0E0', icon: GoogleChatIcon, From 30cb108b30fd71104ea33b3e205bfaba95761646 Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 25 Feb 2026 13:26:57 -0800 Subject: [PATCH 3/4] lint --- apps/docs/components/icons.tsx | 31 +++++++++------------- apps/docs/components/ui/icon-mapping.ts | 12 ++++----- apps/docs/content/docs/en/tools/meta.json | 2 +- apps/sim/components/icons.tsx | 31 +++++++++------------- apps/sim/lib/oauth/oauth.ts | 2 +- apps/sim/tools/google_chat/send_message.ts | 5 +--- apps/sim/tools/registry.ts | 2 +- 7 files changed, 36 insertions(+), 49 deletions(-) diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 58f5ef6cba..c6217e64ac 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -1304,35 +1304,30 @@ export function GoogleCalendarIcon(props: SVGProps) { export function GoogleChatIcon(props: SVGProps) { return ( - + ) diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index 407d6bd578..1cb91c66bc 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -38,8 +38,8 @@ import { EyeIcon, FirecrawlIcon, FirefliesIcon, - GitLabIcon, GithubIcon, + GitLabIcon, GmailIcon, GongIcon, GoogleBooksIcon, @@ -73,9 +73,9 @@ import { LinearIcon, LinkedInIcon, LinkupIcon, - MailServerIcon, MailchimpIcon, MailgunIcon, + MailServerIcon, Mem0Icon, MicrosoftDataverseIcon, MicrosoftExcelIcon, @@ -108,8 +108,6 @@ import { ResendIcon, RevenueCatIcon, S3Icon, - SQSIcon, - STTIcon, SalesforceIcon, SearchIcon, SendgridIcon, @@ -121,17 +119,19 @@ import { SimilarwebIcon, SlackIcon, SmtpIcon, + SQSIcon, SshIcon, + STTIcon, StagehandIcon, StripeIcon, SupabaseIcon, - TTSIcon, TavilyIcon, TelegramIcon, TextractIcon, TinybirdIcon, TranslateIcon, TrelloIcon, + TTSIcon, TwilioIcon, TypeformIcon, UpstashIcon, @@ -142,11 +142,11 @@ import { WhatsAppIcon, WikipediaIcon, WordpressIcon, + xIcon, YouTubeIcon, ZendeskIcon, ZepIcon, ZoomIcon, - xIcon, } from '@/components/icons' type IconComponent = ComponentType> diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index 8fb3410b68..8a943b0b32 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -147,4 +147,4 @@ "zep", "zoom" ] -} \ No newline at end of file +} diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 58f5ef6cba..c6217e64ac 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -1304,35 +1304,30 @@ export function GoogleCalendarIcon(props: SVGProps) { export function GoogleChatIcon(props: SVGProps) { return ( - + ) diff --git a/apps/sim/lib/oauth/oauth.ts b/apps/sim/lib/oauth/oauth.ts index 158361e031..02dc76608c 100644 --- a/apps/sim/lib/oauth/oauth.ts +++ b/apps/sim/lib/oauth/oauth.ts @@ -9,10 +9,10 @@ import { GithubIcon, GmailIcon, GoogleCalendarIcon, + GoogleChatIcon, GoogleDocsIcon, GoogleDriveIcon, GoogleFormsIcon, - GoogleChatIcon, GoogleGroupsIcon, GoogleIcon, GoogleSheetsIcon, diff --git a/apps/sim/tools/google_chat/send_message.ts b/apps/sim/tools/google_chat/send_message.ts index e50156f316..504e6fee8f 100644 --- a/apps/sim/tools/google_chat/send_message.ts +++ b/apps/sim/tools/google_chat/send_message.ts @@ -48,10 +48,7 @@ export const sendMessageTool: ToolConfig Date: Wed, 25 Feb 2026 13:53:59 -0800 Subject: [PATCH 4/4] fix(google-chat): add OAuth provider registration to auth.ts --- apps/sim/lib/auth/auth.ts | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/apps/sim/lib/auth/auth.ts b/apps/sim/lib/auth/auth.ts index 91eb88b1d3..92ca8d2760 100644 --- a/apps/sim/lib/auth/auth.ts +++ b/apps/sim/lib/auth/auth.ts @@ -486,6 +486,7 @@ export const auth = betterAuth({ 'google-forms', 'google-vault', 'google-groups', + 'google-chat', 'vertex-ai', 'github-repo', 'microsoft-dataverse', @@ -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,