From a973cc4be88b2d9403f0a1ccc427722a649e2ae5 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 25 Feb 2026 12:08:28 -0800 Subject: [PATCH 1/7] feat(bigquery): add Google BigQuery integration --- apps/docs/components/icons.tsx | 17 ++ apps/docs/components/ui/icon-mapping.ts | 14 +- .../content/docs/en/tools/google_bigquery.mdx | 139 ++++++++++ apps/docs/content/docs/en/tools/meta.json | 3 +- .../components/oauth-required-modal.tsx | 1 + apps/sim/blocks/blocks/google_bigquery.ts | 250 ++++++++++++++++++ apps/sim/blocks/registry.ts | 2 + apps/sim/components/icons.tsx | 17 ++ apps/sim/lib/oauth/oauth.ts | 9 + apps/sim/lib/oauth/types.ts | 2 + apps/sim/tools/google_bigquery/get_table.ts | 104 ++++++++ apps/sim/tools/google_bigquery/index.ts | 5 + apps/sim/tools/google_bigquery/insert_rows.ts | 131 +++++++++ .../tools/google_bigquery/list_datasets.ts | 101 +++++++ apps/sim/tools/google_bigquery/list_tables.ts | 112 ++++++++ apps/sim/tools/google_bigquery/query.ts | 126 +++++++++ apps/sim/tools/google_bigquery/types.ts | 119 +++++++++ apps/sim/tools/registry.ts | 12 + 18 files changed, 1157 insertions(+), 7 deletions(-) create mode 100644 apps/docs/content/docs/en/tools/google_bigquery.mdx create mode 100644 apps/sim/blocks/blocks/google_bigquery.ts create mode 100644 apps/sim/tools/google_bigquery/get_table.ts create mode 100644 apps/sim/tools/google_bigquery/index.ts create mode 100644 apps/sim/tools/google_bigquery/insert_rows.ts create mode 100644 apps/sim/tools/google_bigquery/list_datasets.ts create mode 100644 apps/sim/tools/google_bigquery/list_tables.ts create mode 100644 apps/sim/tools/google_bigquery/query.ts create mode 100644 apps/sim/tools/google_bigquery/types.ts diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index dcd5741f2b..43c5c2e591 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -3430,6 +3430,23 @@ export const ResendIcon = (props: SVGProps) => ( ) +export const GoogleBigQueryIcon = (props: SVGProps) => ( + + + + + +) + export const GoogleVaultIcon = (props: SVGProps) => ( > @@ -187,6 +188,7 @@ export const blockTypeToIconMap: Record = { gitlab: GitLabIcon, gmail_v2: GmailIcon, gong: GongIcon, + google_bigquery: GoogleBigQueryIcon, google_books: GoogleBooksIcon, google_calendar_v2: GoogleCalendarIcon, google_docs: GoogleDocsIcon, diff --git a/apps/docs/content/docs/en/tools/google_bigquery.mdx b/apps/docs/content/docs/en/tools/google_bigquery.mdx new file mode 100644 index 0000000000..e13a87a4ff --- /dev/null +++ b/apps/docs/content/docs/en/tools/google_bigquery.mdx @@ -0,0 +1,139 @@ +--- +title: Google BigQuery +description: Query, list, and insert data in Google BigQuery +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## Usage Instructions + +Connect to Google BigQuery to run SQL queries, list datasets and tables, get table metadata, and insert rows. + + + +## Tools + +### `google_bigquery_query` + +Run a SQL query against Google BigQuery and return the results + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `projectId` | string | Yes | Google Cloud project ID | +| `query` | string | Yes | SQL query to execute | +| `useLegacySql` | boolean | No | Whether to use legacy SQL syntax \(default: false\) | +| `maxResults` | number | No | Maximum number of rows to return | +| `defaultDatasetId` | string | No | Default dataset for unqualified table names | +| `location` | string | No | Processing location \(e.g., "US", "EU"\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `columns` | json | Array of column names from the query result | +| `rows` | json | Array of row objects with column values | +| `totalRows` | string | Total number of rows in the result | +| `jobComplete` | boolean | Whether the query completed within the timeout | +| `totalBytesProcessed` | string | Total bytes processed by the query | +| `cacheHit` | boolean | Whether the query result was served from cache | +| `jobReference` | json | Job reference with projectId, jobId, and location \(useful when jobComplete is false\) | +| `pageToken` | string | Token for fetching additional result pages | + +### `google_bigquery_list_datasets` + +List all datasets in a Google BigQuery project + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `projectId` | string | Yes | Google Cloud project ID | +| `maxResults` | number | No | Maximum number of datasets to return | +| `pageToken` | string | No | Token for pagination | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `datasets` | json | Array of dataset objects | +| `nextPageToken` | string | Token for fetching next page of results | + +### `google_bigquery_list_tables` + +List all tables in a Google BigQuery dataset + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `projectId` | string | Yes | Google Cloud project ID | +| `datasetId` | string | Yes | BigQuery dataset ID | +| `maxResults` | number | No | Maximum number of tables to return | +| `pageToken` | string | No | Token for pagination | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `tables` | json | Array of table objects | +| `totalItems` | number | Total number of tables in the dataset | +| `nextPageToken` | string | Token for fetching next page of results | + +### `google_bigquery_get_table` + +Get metadata and schema for a Google BigQuery table + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `projectId` | string | Yes | Google Cloud project ID | +| `datasetId` | string | Yes | BigQuery dataset ID | +| `tableId` | string | Yes | BigQuery table ID | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `tableId` | string | Table ID | +| `datasetId` | string | Dataset ID | +| `projectId` | string | Project ID | +| `type` | string | Table type \(TABLE, VIEW, etc.\) | +| `description` | string | Table description | +| `numRows` | string | Total number of rows | +| `numBytes` | string | Total size in bytes | +| `schema` | json | Array of column definitions with name, type, mode, and description | +| `creationTime` | string | Table creation time \(milliseconds since epoch\) | +| `lastModifiedTime` | string | Last modification time \(milliseconds since epoch\) | +| `location` | string | Data location | + +### `google_bigquery_insert_rows` + +Insert rows into a Google BigQuery table using streaming insert + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `projectId` | string | Yes | Google Cloud project ID | +| `datasetId` | string | Yes | BigQuery dataset ID | +| `tableId` | string | Yes | BigQuery table ID | +| `rows` | string | Yes | JSON array of row objects to insert | +| `skipInvalidRows` | boolean | No | Whether to insert valid rows even if some are invalid | +| `ignoreUnknownValues` | boolean | No | Whether to ignore columns not in the table schema | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `insertedRows` | number | Number of rows successfully inserted | +| `errors` | json | Array of per-row insertion errors \(empty if all succeeded\) | + + diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index 9fc1cc577e..9a122688e8 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -37,6 +37,7 @@ "gitlab", "gmail", "gong", + "google_bigquery", "google_books", "google_calendar", "google_docs", @@ -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..6c66ffead6 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 @@ -44,6 +44,7 @@ const SCOPE_DESCRIPTIONS: Record = { 'https://www.googleapis.com/auth/userinfo.profile': 'View basic profile info', 'https://www.googleapis.com/auth/forms.body': 'View and manage Google Forms', 'https://www.googleapis.com/auth/forms.responses.readonly': 'View responses to Google Forms', + 'https://www.googleapis.com/auth/bigquery': 'View and manage data in Google BigQuery', 'https://www.googleapis.com/auth/ediscovery': 'Access Google Vault for eDiscovery', 'https://www.googleapis.com/auth/devstorage.read_only': 'Read files from Google Cloud Storage', 'https://www.googleapis.com/auth/admin.directory.group': 'Manage Google Workspace groups', diff --git a/apps/sim/blocks/blocks/google_bigquery.ts b/apps/sim/blocks/blocks/google_bigquery.ts new file mode 100644 index 0000000000..ab9495c185 --- /dev/null +++ b/apps/sim/blocks/blocks/google_bigquery.ts @@ -0,0 +1,250 @@ +import { GoogleBigQueryIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import { AuthMode } from '@/blocks/types' + +export const GoogleBigQueryBlock: BlockConfig = { + type: 'google_bigquery', + name: 'Google BigQuery', + description: 'Query, list, and insert data in Google BigQuery', + longDescription: + 'Connect to Google BigQuery to run SQL queries, list datasets and tables, get table metadata, and insert rows.', + docsLink: 'https://docs.sim.ai/tools/google-bigquery', + category: 'tools', + bgColor: '#E0E0E0', + icon: GoogleBigQueryIcon, + authMode: AuthMode.OAuth, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'Run Query', id: 'query' }, + { label: 'List Datasets', id: 'list_datasets' }, + { label: 'List Tables', id: 'list_tables' }, + { label: 'Get Table', id: 'get_table' }, + { label: 'Insert Rows', id: 'insert_rows' }, + ], + value: () => 'query', + }, + + { + id: 'credential', + title: 'Google Account', + type: 'oauth-input', + canonicalParamId: 'oauthCredential', + mode: 'basic', + required: true, + serviceId: 'google-bigquery', + requiredScopes: ['https://www.googleapis.com/auth/bigquery'], + placeholder: 'Select Google account', + }, + { + id: 'manualCredential', + title: 'Google Account', + type: 'short-input', + canonicalParamId: 'oauthCredential', + mode: 'advanced', + placeholder: 'Enter credential ID', + required: true, + }, + + { + id: 'projectId', + title: 'Project ID', + type: 'short-input', + placeholder: 'Enter Google Cloud project ID', + required: true, + }, + + { + id: 'query', + title: 'SQL Query', + type: 'long-input', + placeholder: 'SELECT * FROM `project.dataset.table` LIMIT 100', + condition: { field: 'operation', value: 'query' }, + required: { field: 'operation', value: 'query' }, + wandConfig: { + enabled: true, + prompt: `Generate a BigQuery Standard SQL query based on the user's description. +The query should: +- Use Standard SQL syntax (not Legacy SQL) +- Be well-formatted and efficient +- Include appropriate LIMIT clauses when applicable + +Examples: +- "get all users" -> SELECT * FROM \`project.dataset.users\` LIMIT 1000 +- "count orders by status" -> SELECT status, COUNT(*) as count FROM \`project.dataset.orders\` GROUP BY status +- "recent events" -> SELECT * FROM \`project.dataset.events\` ORDER BY created_at DESC LIMIT 100 + +Return ONLY the SQL query - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the query you want to run...', + }, + }, + { + id: 'useLegacySql', + title: 'Use Legacy SQL', + type: 'switch', + condition: { field: 'operation', value: 'query' }, + }, + { + id: 'maxResults', + title: 'Max Results', + type: 'short-input', + placeholder: 'Maximum rows to return', + condition: { field: 'operation', value: ['query', 'list_datasets', 'list_tables'] }, + }, + { + id: 'defaultDatasetId', + title: 'Default Dataset', + type: 'short-input', + placeholder: 'Default dataset for unqualified table names', + condition: { field: 'operation', value: 'query' }, + }, + { + id: 'location', + title: 'Location', + type: 'short-input', + placeholder: 'Processing location (e.g., US, EU)', + condition: { field: 'operation', value: 'query' }, + }, + + { + id: 'datasetId', + title: 'Dataset ID', + type: 'short-input', + placeholder: 'Enter BigQuery dataset ID', + condition: { field: 'operation', value: ['list_tables', 'get_table', 'insert_rows'] }, + required: { field: 'operation', value: ['list_tables', 'get_table', 'insert_rows'] }, + }, + + { + id: 'tableId', + title: 'Table ID', + type: 'short-input', + placeholder: 'Enter BigQuery table ID', + condition: { field: 'operation', value: ['get_table', 'insert_rows'] }, + required: { field: 'operation', value: ['get_table', 'insert_rows'] }, + }, + + { + id: 'rows', + title: 'Rows', + type: 'long-input', + placeholder: '[{"column1": "value1", "column2": 42}]', + condition: { field: 'operation', value: 'insert_rows' }, + required: { field: 'operation', value: 'insert_rows' }, + wandConfig: { + enabled: true, + prompt: `Generate a JSON array of row objects for BigQuery insertion based on the user's description. +Each row should be a JSON object where keys are column names and values match the expected types. + +Examples: +- "3 users" -> [{"name": "Alice", "email": "alice@example.com"}, {"name": "Bob", "email": "bob@example.com"}, {"name": "Charlie", "email": "charlie@example.com"}] +- "order record" -> [{"order_id": "ORD-001", "amount": 99.99, "status": "pending"}] + +Return ONLY the JSON array - no explanations, no wrapping, no extra text.`, + placeholder: 'Describe the rows to insert...', + generationType: 'json-object', + }, + }, + { + id: 'skipInvalidRows', + title: 'Skip Invalid Rows', + type: 'switch', + condition: { field: 'operation', value: 'insert_rows' }, + }, + { + id: 'ignoreUnknownValues', + title: 'Ignore Unknown Values', + type: 'switch', + condition: { field: 'operation', value: 'insert_rows' }, + }, + + { + id: 'pageToken', + title: 'Page Token', + type: 'short-input', + placeholder: 'Pagination token', + condition: { field: 'operation', value: ['list_datasets', 'list_tables'] }, + }, + ], + tools: { + access: [ + 'google_bigquery_query', + 'google_bigquery_list_datasets', + 'google_bigquery_list_tables', + 'google_bigquery_get_table', + 'google_bigquery_insert_rows', + ], + config: { + tool: (params) => { + switch (params.operation) { + case 'query': + return 'google_bigquery_query' + case 'list_datasets': + return 'google_bigquery_list_datasets' + case 'list_tables': + return 'google_bigquery_list_tables' + case 'get_table': + return 'google_bigquery_get_table' + case 'insert_rows': + return 'google_bigquery_insert_rows' + default: + throw new Error(`Invalid Google BigQuery operation: ${params.operation}`) + } + }, + params: (params) => { + const { oauthCredential, rows, maxResults, ...rest } = params + return { + ...rest, + oauthCredential, + ...(rows && { rows: typeof rows === 'string' ? rows : JSON.stringify(rows) }), + ...(maxResults !== undefined && maxResults !== '' && { maxResults: Number(maxResults) }), + } + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + oauthCredential: { type: 'string', description: 'Google BigQuery OAuth credential' }, + projectId: { type: 'string', description: 'Google Cloud project ID' }, + query: { type: 'string', description: 'SQL query to execute' }, + useLegacySql: { type: 'boolean', description: 'Whether to use legacy SQL syntax' }, + maxResults: { type: 'number', description: 'Maximum number of results to return' }, + defaultDatasetId: { type: 'string', description: 'Default dataset for unqualified table names' }, + location: { type: 'string', description: 'Processing location' }, + datasetId: { type: 'string', description: 'BigQuery dataset ID' }, + tableId: { type: 'string', description: 'BigQuery table ID' }, + rows: { type: 'string', description: 'JSON array of row objects to insert' }, + skipInvalidRows: { type: 'boolean', description: 'Whether to skip invalid rows during insert' }, + ignoreUnknownValues: { type: 'boolean', description: 'Whether to ignore unknown column values' }, + pageToken: { type: 'string', description: 'Pagination token' }, + }, + outputs: { + columns: { type: 'json', description: 'Array of column names (query)' }, + rows: { type: 'json', description: 'Array of row objects (query)' }, + totalRows: { type: 'string', description: 'Total number of rows (query)' }, + jobComplete: { type: 'boolean', description: 'Whether the query completed (query)' }, + totalBytesProcessed: { type: 'string', description: 'Bytes processed (query)' }, + cacheHit: { type: 'boolean', description: 'Whether result was cached (query)' }, + jobReference: { type: 'json', description: 'Job reference for incomplete queries (query)' }, + pageToken: { type: 'string', description: 'Token for additional result pages (query)' }, + datasets: { type: 'json', description: 'Array of dataset objects (list_datasets)' }, + tables: { type: 'json', description: 'Array of table objects (list_tables)' }, + totalItems: { type: 'number', description: 'Total items count (list_tables)' }, + tableId: { type: 'string', description: 'Table ID (get_table)' }, + datasetId: { type: 'string', description: 'Dataset ID (get_table)' }, + type: { type: 'string', description: 'Table type (get_table)' }, + description: { type: 'string', description: 'Table description (get_table)' }, + numRows: { type: 'string', description: 'Row count (get_table)' }, + numBytes: { type: 'string', description: 'Size in bytes (get_table)' }, + schema: { type: 'json', description: 'Column definitions (get_table)' }, + creationTime: { type: 'string', description: 'Creation time (get_table)' }, + lastModifiedTime: { type: 'string', description: 'Last modified time (get_table)' }, + location: { type: 'string', description: 'Data location (get_table)' }, + insertedRows: { type: 'number', description: 'Rows inserted (insert_rows)' }, + errors: { type: 'json', description: 'Insert errors (insert_rows)' }, + 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..d9b2affdb3 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -43,6 +43,7 @@ import { GitLabBlock } from '@/blocks/blocks/gitlab' import { GmailBlock, GmailV2Block } from '@/blocks/blocks/gmail' import { GongBlock } from '@/blocks/blocks/gong' import { GoogleSearchBlock } from '@/blocks/blocks/google' +import { GoogleBigQueryBlock } from '@/blocks/blocks/google_bigquery' import { GoogleBooksBlock } from '@/blocks/blocks/google_books' import { GoogleCalendarBlock, GoogleCalendarV2Block } from '@/blocks/blocks/google_calendar' import { GoogleDocsBlock } from '@/blocks/blocks/google_docs' @@ -240,6 +241,7 @@ export const registry: Record = { google_sheets_v2: GoogleSheetsV2Block, google_slides: GoogleSlidesBlock, google_slides_v2: GoogleSlidesV2Block, + google_bigquery: GoogleBigQueryBlock, google_vault: GoogleVaultBlock, grafana: GrafanaBlock, grain: GrainBlock, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index dcd5741f2b..43c5c2e591 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -3430,6 +3430,23 @@ export const ResendIcon = (props: SVGProps) => ( ) +export const GoogleBigQueryIcon = (props: SVGProps) => ( + + + + + +) + export const GoogleVaultIcon = (props: SVGProps) => ( = { baseProviderIcon: GoogleIcon, scopes: ['https://www.googleapis.com/auth/calendar'], }, + 'google-bigquery': { + name: 'Google BigQuery', + description: 'Query, list, and insert data in Google BigQuery.', + providerId: 'google-bigquery', + icon: GoogleBigQueryIcon, + baseProviderIcon: GoogleIcon, + scopes: ['https://www.googleapis.com/auth/bigquery'], + }, 'google-vault': { name: 'Google Vault', description: 'Search, export, and manage matters/holds via Google Vault.', diff --git a/apps/sim/lib/oauth/types.ts b/apps/sim/lib/oauth/types.ts index d5114a38bc..70229738ab 100644 --- a/apps/sim/lib/oauth/types.ts +++ b/apps/sim/lib/oauth/types.ts @@ -7,6 +7,7 @@ export type OAuthProvider = | 'google-docs' | 'google-sheets' | 'google-calendar' + | 'google-bigquery' | 'google-vault' | 'google-forms' | 'google-groups' @@ -52,6 +53,7 @@ export type OAuthService = | 'google-docs' | 'google-sheets' | 'google-calendar' + | 'google-bigquery' | 'google-vault' | 'google-forms' | 'google-groups' diff --git a/apps/sim/tools/google_bigquery/get_table.ts b/apps/sim/tools/google_bigquery/get_table.ts new file mode 100644 index 0000000000..62c85f3c30 --- /dev/null +++ b/apps/sim/tools/google_bigquery/get_table.ts @@ -0,0 +1,104 @@ +import type { + GoogleBigQueryGetTableParams, + GoogleBigQueryGetTableResponse, +} from '@/tools/google_bigquery/types' +import type { ToolConfig } from '@/tools/types' + +export const getTableTool: ToolConfig< + GoogleBigQueryGetTableParams, + GoogleBigQueryGetTableResponse +> = { + id: 'google_bigquery_get_table', + name: 'BigQuery Get Table', + description: 'Get metadata and schema for a Google BigQuery table', + version: '1.0.0', + + oauth: { + required: true, + provider: 'google-bigquery', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'OAuth access token', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Google Cloud project ID', + }, + datasetId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'BigQuery dataset ID', + }, + tableId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'BigQuery table ID', + }, + }, + + request: { + url: (params) => + `https://bigquery.googleapis.com/bigquery/v2/projects/${encodeURIComponent(params.projectId)}/datasets/${encodeURIComponent(params.datasetId)}/tables/${encodeURIComponent(params.tableId)}`, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + const errorMessage = data.error?.message || 'Failed to get BigQuery table' + throw new Error(errorMessage) + } + + const schema = (data.schema?.fields ?? []).map( + (f: { name: string; type: string; mode?: string; description?: string }) => ({ + name: f.name, + type: f.type, + mode: f.mode ?? null, + description: f.description ?? null, + }) + ) + + return { + success: true, + output: { + tableId: data.tableReference?.tableId ?? null, + datasetId: data.tableReference?.datasetId ?? null, + projectId: data.tableReference?.projectId ?? null, + type: data.type ?? null, + description: data.description ?? null, + numRows: data.numRows ?? null, + numBytes: data.numBytes ?? null, + schema, + creationTime: data.creationTime ?? null, + lastModifiedTime: data.lastModifiedTime ?? null, + location: data.location ?? null, + }, + } + }, + + outputs: { + tableId: { type: 'string', description: 'Table ID' }, + datasetId: { type: 'string', description: 'Dataset ID' }, + projectId: { type: 'string', description: 'Project ID' }, + type: { type: 'string', description: 'Table type (TABLE, VIEW, etc.)' }, + description: { type: 'string', description: 'Table description' }, + numRows: { type: 'string', description: 'Total number of rows' }, + numBytes: { type: 'string', description: 'Total size in bytes' }, + schema: { type: 'json', description: 'Array of column definitions with name, type, mode, and description' }, + creationTime: { type: 'string', description: 'Table creation time (milliseconds since epoch)' }, + lastModifiedTime: { type: 'string', description: 'Last modification time (milliseconds since epoch)' }, + location: { type: 'string', description: 'Data location' }, + }, +} diff --git a/apps/sim/tools/google_bigquery/index.ts b/apps/sim/tools/google_bigquery/index.ts new file mode 100644 index 0000000000..3362d7a3e7 --- /dev/null +++ b/apps/sim/tools/google_bigquery/index.ts @@ -0,0 +1,5 @@ +export { getTableTool } from '@/tools/google_bigquery/get_table' +export { insertRowsTool } from '@/tools/google_bigquery/insert_rows' +export { listDatasetsTool } from '@/tools/google_bigquery/list_datasets' +export { listTablesTool } from '@/tools/google_bigquery/list_tables' +export { queryTool } from '@/tools/google_bigquery/query' diff --git a/apps/sim/tools/google_bigquery/insert_rows.ts b/apps/sim/tools/google_bigquery/insert_rows.ts new file mode 100644 index 0000000000..be0650637e --- /dev/null +++ b/apps/sim/tools/google_bigquery/insert_rows.ts @@ -0,0 +1,131 @@ +import type { + GoogleBigQueryInsertRowsParams, + GoogleBigQueryInsertRowsResponse, +} from '@/tools/google_bigquery/types' +import type { ToolConfig } from '@/tools/types' + +export const insertRowsTool: ToolConfig< + GoogleBigQueryInsertRowsParams, + GoogleBigQueryInsertRowsResponse +> = { + id: 'google_bigquery_insert_rows', + name: 'BigQuery Insert Rows', + description: 'Insert rows into a Google BigQuery table using streaming insert', + version: '1.0.0', + + oauth: { + required: true, + provider: 'google-bigquery', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'OAuth access token', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Google Cloud project ID', + }, + datasetId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'BigQuery dataset ID', + }, + tableId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'BigQuery table ID', + }, + rows: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'JSON array of row objects to insert', + }, + skipInvalidRows: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether to insert valid rows even if some are invalid', + }, + ignoreUnknownValues: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether to ignore columns not in the table schema', + }, + }, + + request: { + url: (params) => + `https://bigquery.googleapis.com/bigquery/v2/projects/${encodeURIComponent(params.projectId)}/datasets/${encodeURIComponent(params.datasetId)}/tables/${encodeURIComponent(params.tableId)}/insertAll`, + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const parsedRows = typeof params.rows === 'string' ? JSON.parse(params.rows) : params.rows + const rows = (parsedRows as Record[]).map( + (row: Record) => ({ json: row }) + ) + + const body: Record = { rows } + if (params.skipInvalidRows !== undefined) body.skipInvalidRows = params.skipInvalidRows + if (params.ignoreUnknownValues !== undefined) + body.ignoreUnknownValues = params.ignoreUnknownValues + + return body + }, + }, + + transformResponse: async (response: Response, params?: GoogleBigQueryInsertRowsParams) => { + const data = await response.json() + if (!response.ok) { + const errorMessage = data.error?.message || 'Failed to insert rows into BigQuery table' + throw new Error(errorMessage) + } + + const insertErrors = data.insertErrors ?? [] + const errors = insertErrors.map( + (err: { + index: number + errors: Array<{ reason?: string; location?: string; message?: string }> + }) => ({ + index: err.index, + errors: err.errors.map((e) => ({ + reason: e.reason ?? null, + location: e.location ?? null, + message: e.message ?? null, + })), + }) + ) + + let totalRows = 0 + if (params?.rows) { + const parsed = typeof params.rows === 'string' ? JSON.parse(params.rows) : params.rows + totalRows = Array.isArray(parsed) ? parsed.length : 0 + } + const failedIndexes = new Set(insertErrors.map((e: { index: number }) => e.index)) + + return { + success: true, + output: { + insertedRows: totalRows - failedIndexes.size, + errors, + }, + } + }, + + outputs: { + insertedRows: { type: 'number', description: 'Number of rows successfully inserted' }, + errors: { type: 'json', description: 'Array of per-row insertion errors (empty if all succeeded)' }, + }, +} diff --git a/apps/sim/tools/google_bigquery/list_datasets.ts b/apps/sim/tools/google_bigquery/list_datasets.ts new file mode 100644 index 0000000000..ec6b318496 --- /dev/null +++ b/apps/sim/tools/google_bigquery/list_datasets.ts @@ -0,0 +1,101 @@ +import type { + GoogleBigQueryListDatasetsParams, + GoogleBigQueryListDatasetsResponse, +} from '@/tools/google_bigquery/types' +import type { ToolConfig } from '@/tools/types' + +export const listDatasetsTool: ToolConfig< + GoogleBigQueryListDatasetsParams, + GoogleBigQueryListDatasetsResponse +> = { + id: 'google_bigquery_list_datasets', + name: 'BigQuery List Datasets', + description: 'List all datasets in a Google BigQuery project', + version: '1.0.0', + + oauth: { + required: true, + provider: 'google-bigquery', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'OAuth access token', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Google Cloud project ID', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of datasets to return', + }, + pageToken: { + type: 'string', + required: false, + visibility: 'hidden', + description: 'Token for pagination', + }, + }, + + request: { + url: (params) => { + const url = new URL( + `https://bigquery.googleapis.com/bigquery/v2/projects/${encodeURIComponent(params.projectId)}/datasets` + ) + if (params.maxResults !== undefined && params.maxResults !== null) { + const maxResults = Number(params.maxResults) + if (Number.isFinite(maxResults) && maxResults > 0) { + url.searchParams.set('maxResults', String(maxResults)) + } + } + if (params.pageToken) url.searchParams.set('pageToken', params.pageToken) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + const errorMessage = data.error?.message || 'Failed to list BigQuery datasets' + throw new Error(errorMessage) + } + + const datasets = (data.datasets ?? []).map( + (ds: { + datasetReference: { datasetId: string; projectId: string } + friendlyName?: string + location?: string + }) => ({ + datasetId: ds.datasetReference.datasetId, + projectId: ds.datasetReference.projectId, + friendlyName: ds.friendlyName ?? null, + location: ds.location ?? null, + }) + ) + + return { + success: true, + output: { + datasets, + nextPageToken: data.nextPageToken ?? null, + }, + } + }, + + outputs: { + datasets: { type: 'json', description: 'Array of dataset objects' }, + nextPageToken: { type: 'string', description: 'Token for fetching next page of results' }, + }, +} diff --git a/apps/sim/tools/google_bigquery/list_tables.ts b/apps/sim/tools/google_bigquery/list_tables.ts new file mode 100644 index 0000000000..55ebdbf93f --- /dev/null +++ b/apps/sim/tools/google_bigquery/list_tables.ts @@ -0,0 +1,112 @@ +import type { + GoogleBigQueryListTablesParams, + GoogleBigQueryListTablesResponse, +} from '@/tools/google_bigquery/types' +import type { ToolConfig } from '@/tools/types' + +export const listTablesTool: ToolConfig< + GoogleBigQueryListTablesParams, + GoogleBigQueryListTablesResponse +> = { + id: 'google_bigquery_list_tables', + name: 'BigQuery List Tables', + description: 'List all tables in a Google BigQuery dataset', + version: '1.0.0', + + oauth: { + required: true, + provider: 'google-bigquery', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'OAuth access token', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Google Cloud project ID', + }, + datasetId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'BigQuery dataset ID', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of tables to return', + }, + pageToken: { + type: 'string', + required: false, + visibility: 'hidden', + description: 'Token for pagination', + }, + }, + + request: { + url: (params) => { + const url = new URL( + `https://bigquery.googleapis.com/bigquery/v2/projects/${encodeURIComponent(params.projectId)}/datasets/${encodeURIComponent(params.datasetId)}/tables` + ) + if (params.maxResults !== undefined && params.maxResults !== null) { + const maxResults = Number(params.maxResults) + if (Number.isFinite(maxResults) && maxResults > 0) { + url.searchParams.set('maxResults', String(maxResults)) + } + } + if (params.pageToken) url.searchParams.set('pageToken', params.pageToken) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + const errorMessage = data.error?.message || 'Failed to list BigQuery tables' + throw new Error(errorMessage) + } + + const tables = (data.tables ?? []).map( + (t: { + tableReference: { tableId: string; datasetId: string; projectId: string } + type?: string + friendlyName?: string + creationTime?: string + }) => ({ + tableId: t.tableReference.tableId, + datasetId: t.tableReference.datasetId, + projectId: t.tableReference.projectId, + type: t.type ?? null, + friendlyName: t.friendlyName ?? null, + creationTime: t.creationTime ?? null, + }) + ) + + return { + success: true, + output: { + tables, + totalItems: data.totalItems ?? null, + nextPageToken: data.nextPageToken ?? null, + }, + } + }, + + outputs: { + tables: { type: 'json', description: 'Array of table objects' }, + totalItems: { type: 'number', description: 'Total number of tables in the dataset' }, + nextPageToken: { type: 'string', description: 'Token for fetching next page of results' }, + }, +} diff --git a/apps/sim/tools/google_bigquery/query.ts b/apps/sim/tools/google_bigquery/query.ts new file mode 100644 index 0000000000..e908051638 --- /dev/null +++ b/apps/sim/tools/google_bigquery/query.ts @@ -0,0 +1,126 @@ +import type { GoogleBigQueryQueryParams, GoogleBigQueryQueryResponse } from '@/tools/google_bigquery/types' +import type { ToolConfig } from '@/tools/types' + +export const queryTool: ToolConfig = { + id: 'google_bigquery_query', + name: 'BigQuery Run Query', + description: 'Run a SQL query against Google BigQuery and return the results', + version: '1.0.0', + + oauth: { + required: true, + provider: 'google-bigquery', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'OAuth access token', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Google Cloud project ID', + }, + query: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'SQL query to execute', + }, + useLegacySql: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether to use legacy SQL syntax (default: false)', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of rows to return', + }, + defaultDatasetId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Default dataset for unqualified table names', + }, + location: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Processing location (e.g., "US", "EU")', + }, + }, + + request: { + url: (params) => + `https://bigquery.googleapis.com/bigquery/v2/projects/${encodeURIComponent(params.projectId)}/queries`, + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: Record = { + query: params.query, + useLegacySql: params.useLegacySql ?? false, + } + if (params.maxResults !== undefined) body.maxResults = Number(params.maxResults) + if (params.defaultDatasetId) { + body.defaultDataset = { + projectId: params.projectId, + datasetId: params.defaultDatasetId, + } + } + if (params.location) body.location = params.location + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + const errorMessage = data.error?.message || 'Failed to execute BigQuery query' + throw new Error(errorMessage) + } + + const columns = (data.schema?.fields ?? []).map((f: { name: string }) => f.name) + const rows = (data.rows ?? []).map((row: { f: Array<{ v: unknown }> }) => { + const obj: Record = {} + row.f.forEach((field, index) => { + obj[columns[index]] = field.v ?? null + }) + return obj + }) + + return { + success: true, + output: { + columns, + rows, + totalRows: data.totalRows ?? null, + jobComplete: data.jobComplete ?? false, + totalBytesProcessed: data.totalBytesProcessed ?? null, + cacheHit: data.cacheHit ?? null, + jobReference: data.jobReference ?? null, + pageToken: data.pageToken ?? null, + }, + } + }, + + outputs: { + columns: { type: 'json', description: 'Array of column names from the query result' }, + rows: { type: 'json', description: 'Array of row objects with column values' }, + totalRows: { type: 'string', description: 'Total number of rows in the result' }, + jobComplete: { type: 'boolean', description: 'Whether the query completed within the timeout' }, + totalBytesProcessed: { type: 'string', description: 'Total bytes processed by the query' }, + cacheHit: { type: 'boolean', description: 'Whether the query result was served from cache' }, + jobReference: { type: 'json', description: 'Job reference with projectId, jobId, and location (useful when jobComplete is false)' }, + pageToken: { type: 'string', description: 'Token for fetching additional result pages' }, + }, +} diff --git a/apps/sim/tools/google_bigquery/types.ts b/apps/sim/tools/google_bigquery/types.ts new file mode 100644 index 0000000000..c7432e0dea --- /dev/null +++ b/apps/sim/tools/google_bigquery/types.ts @@ -0,0 +1,119 @@ +import type { ToolResponse } from '@/tools/types' + +export interface GoogleBigQueryBaseParams { + accessToken: string + projectId: string +} + +export interface GoogleBigQueryQueryParams extends GoogleBigQueryBaseParams { + query: string + useLegacySql?: boolean + maxResults?: number + defaultDatasetId?: string + location?: string +} + +export interface GoogleBigQueryListDatasetsParams extends GoogleBigQueryBaseParams { + maxResults?: number + pageToken?: string +} + +export interface GoogleBigQueryListTablesParams extends GoogleBigQueryBaseParams { + datasetId: string + maxResults?: number + pageToken?: string +} + +export interface GoogleBigQueryGetTableParams extends GoogleBigQueryBaseParams { + datasetId: string + tableId: string +} + +export interface GoogleBigQueryInsertRowsParams extends GoogleBigQueryBaseParams { + datasetId: string + tableId: string + rows: string + skipInvalidRows?: boolean + ignoreUnknownValues?: boolean +} + +export interface GoogleBigQueryJobReference { + projectId: string + jobId: string + location: string +} + +export interface GoogleBigQueryQueryResponse extends ToolResponse { + output: { + columns: string[] + rows: Record[] + totalRows: string | null + jobComplete: boolean + totalBytesProcessed: string | null + cacheHit: boolean | null + jobReference: GoogleBigQueryJobReference | null + pageToken: string | null + } +} + +export interface GoogleBigQueryListDatasetsResponse extends ToolResponse { + output: { + datasets: Array<{ + datasetId: string + projectId: string + friendlyName: string | null + location: string | null + }> + nextPageToken: string | null + } +} + +export interface GoogleBigQueryListTablesResponse extends ToolResponse { + output: { + tables: Array<{ + tableId: string + datasetId: string + projectId: string + type: string | null + friendlyName: string | null + creationTime: string | null + }> + totalItems: number | null + nextPageToken: string | null + } +} + +export interface GoogleBigQueryGetTableResponse extends ToolResponse { + output: { + tableId: string + datasetId: string + projectId: string + type: string | null + description: string | null + numRows: string | null + numBytes: string | null + schema: Array<{ + name: string + type: string + mode: string | null + description: string | null + }> + creationTime: string | null + lastModifiedTime: string | null + location: string | null + } +} + +export interface GoogleBigQueryInsertRowsResponse extends ToolResponse { + output: { + insertedRows: number + errors: Array<{ + index: number + errors: Array<{ + reason: string | null + location: string | null + message: string | null + }> + }> + } +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 5a2f5787c7..527781b558 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -747,6 +747,13 @@ import { listMattersHoldsTool, listMattersTool, } from '@/tools/google_vault' +import { + getTableTool as bigqueryGetTableTool, + insertRowsTool as bigqueryInsertRowsTool, + listDatasetsTool as bigqueryListDatasetsTool, + listTablesTool as bigqueryListTablesTool, + queryTool as bigqueryQueryTool, +} from '@/tools/google_bigquery' import { grafanaCreateAlertRuleTool, grafanaCreateAnnotationTool, @@ -3556,6 +3563,11 @@ export const tools: Record = { wordpress_list_users: wordpressListUsersTool, wordpress_get_user: wordpressGetUserTool, wordpress_search_content: wordpressSearchContentTool, + google_bigquery_query: bigqueryQueryTool, + google_bigquery_list_datasets: bigqueryListDatasetsTool, + google_bigquery_list_tables: bigqueryListTablesTool, + google_bigquery_get_table: bigqueryGetTableTool, + google_bigquery_insert_rows: bigqueryInsertRowsTool, google_vault_create_matters_export: createMattersExportTool, google_vault_list_matters_export: listMattersExportTool, google_vault_create_matters_holds: createMattersHoldsTool, From cd323d8165da8331f970d910e53fe9cbd77c7aea Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 25 Feb 2026 13:04:03 -0800 Subject: [PATCH 2/7] fix(bigquery): add auth provider, fix docsLink and insertedRows count --- apps/sim/blocks/blocks/google_bigquery.ts | 2 +- apps/sim/lib/auth/auth.ts | 41 +++++++++++++++++++ apps/sim/tools/google_bigquery/insert_rows.ts | 14 ++++++- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/apps/sim/blocks/blocks/google_bigquery.ts b/apps/sim/blocks/blocks/google_bigquery.ts index ab9495c185..29477770f5 100644 --- a/apps/sim/blocks/blocks/google_bigquery.ts +++ b/apps/sim/blocks/blocks/google_bigquery.ts @@ -8,7 +8,7 @@ export const GoogleBigQueryBlock: BlockConfig = { description: 'Query, list, and insert data in Google BigQuery', longDescription: 'Connect to Google BigQuery to run SQL queries, list datasets and tables, get table metadata, and insert rows.', - docsLink: 'https://docs.sim.ai/tools/google-bigquery', + docsLink: 'https://docs.sim.ai/tools/google_bigquery', category: 'tools', bgColor: '#E0E0E0', icon: GoogleBigQueryIcon, diff --git a/apps/sim/lib/auth/auth.ts b/apps/sim/lib/auth/auth.ts index 91eb88b1d3..cea2789e9a 100644 --- a/apps/sim/lib/auth/auth.ts +++ b/apps/sim/lib/auth/auth.ts @@ -484,6 +484,7 @@ export const auth = betterAuth({ 'google-docs', 'google-sheets', 'google-forms', + 'google-bigquery', 'google-vault', 'google-groups', 'vertex-ai', @@ -1068,6 +1069,46 @@ export const auth = betterAuth({ } }, }, + { + providerId: 'google-bigquery', + 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/bigquery', + ], + prompt: 'consent', + redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/google-bigquery`, + 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: 'google-vault', clientId: env.GOOGLE_CLIENT_ID as string, diff --git a/apps/sim/tools/google_bigquery/insert_rows.ts b/apps/sim/tools/google_bigquery/insert_rows.ts index be0650637e..4619230ae3 100644 --- a/apps/sim/tools/google_bigquery/insert_rows.ts +++ b/apps/sim/tools/google_bigquery/insert_rows.ts @@ -113,12 +113,22 @@ export const insertRowsTool: ToolConfig< const parsed = typeof params.rows === 'string' ? JSON.parse(params.rows) : params.rows totalRows = Array.isArray(parsed) ? parsed.length : 0 } - const failedIndexes = new Set(insertErrors.map((e: { index: number }) => e.index)) + + // When insertErrors is empty, all rows succeeded. + // When insertErrors is present and skipInvalidRows is false (default), + // the entire batch is rejected — no rows are inserted. + let insertedRows = 0 + if (insertErrors.length === 0) { + insertedRows = totalRows + } else if (params?.skipInvalidRows) { + const failedIndexes = new Set(insertErrors.map((e: { index: number }) => e.index)) + insertedRows = totalRows - failedIndexes.size + } return { success: true, output: { - insertedRows: totalRows - failedIndexes.size, + insertedRows, errors, }, } From d39e63c32461240091a7db052ec704bded7b2455 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 25 Feb 2026 13:15:50 -0800 Subject: [PATCH 3/7] fix(bigquery): set pageToken visibility to user-or-llm for pagination --- apps/sim/tools/google_bigquery/list_datasets.ts | 2 +- apps/sim/tools/google_bigquery/list_tables.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sim/tools/google_bigquery/list_datasets.ts b/apps/sim/tools/google_bigquery/list_datasets.ts index ec6b318496..5e3d6903fb 100644 --- a/apps/sim/tools/google_bigquery/list_datasets.ts +++ b/apps/sim/tools/google_bigquery/list_datasets.ts @@ -40,7 +40,7 @@ export const listDatasetsTool: ToolConfig< pageToken: { type: 'string', required: false, - visibility: 'hidden', + visibility: 'user-or-llm', description: 'Token for pagination', }, }, diff --git a/apps/sim/tools/google_bigquery/list_tables.ts b/apps/sim/tools/google_bigquery/list_tables.ts index 55ebdbf93f..e8d0163c1b 100644 --- a/apps/sim/tools/google_bigquery/list_tables.ts +++ b/apps/sim/tools/google_bigquery/list_tables.ts @@ -46,7 +46,7 @@ export const listTablesTool: ToolConfig< pageToken: { type: 'string', required: false, - visibility: 'hidden', + visibility: 'user-or-llm', description: 'Token for pagination', }, }, From 171f231ee520ce7f389ea49caf32f6422f86fcc8 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 25 Feb 2026 14:00:19 -0800 Subject: [PATCH 4/7] fix(bigquery): use prefixed export names to avoid aliased imports --- apps/sim/tools/google_bigquery/get_table.ts | 2 +- apps/sim/tools/google_bigquery/index.ts | 10 +++++----- apps/sim/tools/google_bigquery/insert_rows.ts | 2 +- .../tools/google_bigquery/list_datasets.ts | 2 +- apps/sim/tools/google_bigquery/list_tables.ts | 2 +- apps/sim/tools/google_bigquery/query.ts | 2 +- apps/sim/tools/registry.ts | 20 +++++++++---------- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/apps/sim/tools/google_bigquery/get_table.ts b/apps/sim/tools/google_bigquery/get_table.ts index 62c85f3c30..29c46aa7df 100644 --- a/apps/sim/tools/google_bigquery/get_table.ts +++ b/apps/sim/tools/google_bigquery/get_table.ts @@ -4,7 +4,7 @@ import type { } from '@/tools/google_bigquery/types' import type { ToolConfig } from '@/tools/types' -export const getTableTool: ToolConfig< +export const googleBigQueryGetTableTool: ToolConfig< GoogleBigQueryGetTableParams, GoogleBigQueryGetTableResponse > = { diff --git a/apps/sim/tools/google_bigquery/index.ts b/apps/sim/tools/google_bigquery/index.ts index 3362d7a3e7..ea1aa73371 100644 --- a/apps/sim/tools/google_bigquery/index.ts +++ b/apps/sim/tools/google_bigquery/index.ts @@ -1,5 +1,5 @@ -export { getTableTool } from '@/tools/google_bigquery/get_table' -export { insertRowsTool } from '@/tools/google_bigquery/insert_rows' -export { listDatasetsTool } from '@/tools/google_bigquery/list_datasets' -export { listTablesTool } from '@/tools/google_bigquery/list_tables' -export { queryTool } from '@/tools/google_bigquery/query' +export { googleBigQueryGetTableTool } from '@/tools/google_bigquery/get_table' +export { googleBigQueryInsertRowsTool } from '@/tools/google_bigquery/insert_rows' +export { googleBigQueryListDatasetsTool } from '@/tools/google_bigquery/list_datasets' +export { googleBigQueryListTablesTool } from '@/tools/google_bigquery/list_tables' +export { googleBigQueryQueryTool } from '@/tools/google_bigquery/query' diff --git a/apps/sim/tools/google_bigquery/insert_rows.ts b/apps/sim/tools/google_bigquery/insert_rows.ts index 4619230ae3..b98c02dadf 100644 --- a/apps/sim/tools/google_bigquery/insert_rows.ts +++ b/apps/sim/tools/google_bigquery/insert_rows.ts @@ -4,7 +4,7 @@ import type { } from '@/tools/google_bigquery/types' import type { ToolConfig } from '@/tools/types' -export const insertRowsTool: ToolConfig< +export const googleBigQueryInsertRowsTool: ToolConfig< GoogleBigQueryInsertRowsParams, GoogleBigQueryInsertRowsResponse > = { diff --git a/apps/sim/tools/google_bigquery/list_datasets.ts b/apps/sim/tools/google_bigquery/list_datasets.ts index 5e3d6903fb..8cb9629763 100644 --- a/apps/sim/tools/google_bigquery/list_datasets.ts +++ b/apps/sim/tools/google_bigquery/list_datasets.ts @@ -4,7 +4,7 @@ import type { } from '@/tools/google_bigquery/types' import type { ToolConfig } from '@/tools/types' -export const listDatasetsTool: ToolConfig< +export const googleBigQueryListDatasetsTool: ToolConfig< GoogleBigQueryListDatasetsParams, GoogleBigQueryListDatasetsResponse > = { diff --git a/apps/sim/tools/google_bigquery/list_tables.ts b/apps/sim/tools/google_bigquery/list_tables.ts index e8d0163c1b..1a0df9c432 100644 --- a/apps/sim/tools/google_bigquery/list_tables.ts +++ b/apps/sim/tools/google_bigquery/list_tables.ts @@ -4,7 +4,7 @@ import type { } from '@/tools/google_bigquery/types' import type { ToolConfig } from '@/tools/types' -export const listTablesTool: ToolConfig< +export const googleBigQueryListTablesTool: ToolConfig< GoogleBigQueryListTablesParams, GoogleBigQueryListTablesResponse > = { diff --git a/apps/sim/tools/google_bigquery/query.ts b/apps/sim/tools/google_bigquery/query.ts index e908051638..815c6f6651 100644 --- a/apps/sim/tools/google_bigquery/query.ts +++ b/apps/sim/tools/google_bigquery/query.ts @@ -1,7 +1,7 @@ import type { GoogleBigQueryQueryParams, GoogleBigQueryQueryResponse } from '@/tools/google_bigquery/types' import type { ToolConfig } from '@/tools/types' -export const queryTool: ToolConfig = { +export const googleBigQueryQueryTool: ToolConfig = { id: 'google_bigquery_query', name: 'BigQuery Run Query', description: 'Run a SQL query against Google BigQuery and return the results', diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 527781b558..ebf5dc39af 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -748,11 +748,11 @@ import { listMattersTool, } from '@/tools/google_vault' import { - getTableTool as bigqueryGetTableTool, - insertRowsTool as bigqueryInsertRowsTool, - listDatasetsTool as bigqueryListDatasetsTool, - listTablesTool as bigqueryListTablesTool, - queryTool as bigqueryQueryTool, + googleBigQueryGetTableTool, + googleBigQueryInsertRowsTool, + googleBigQueryListDatasetsTool, + googleBigQueryListTablesTool, + googleBigQueryQueryTool, } from '@/tools/google_bigquery' import { grafanaCreateAlertRuleTool, @@ -3563,11 +3563,11 @@ export const tools: Record = { wordpress_list_users: wordpressListUsersTool, wordpress_get_user: wordpressGetUserTool, wordpress_search_content: wordpressSearchContentTool, - google_bigquery_query: bigqueryQueryTool, - google_bigquery_list_datasets: bigqueryListDatasetsTool, - google_bigquery_list_tables: bigqueryListTablesTool, - google_bigquery_get_table: bigqueryGetTableTool, - google_bigquery_insert_rows: bigqueryInsertRowsTool, + google_bigquery_query: googleBigQueryQueryTool, + google_bigquery_list_datasets: googleBigQueryListDatasetsTool, + google_bigquery_list_tables: googleBigQueryListTablesTool, + google_bigquery_get_table: googleBigQueryGetTableTool, + google_bigquery_insert_rows: googleBigQueryInsertRowsTool, google_vault_create_matters_export: createMattersExportTool, google_vault_list_matters_export: listMattersExportTool, google_vault_create_matters_holds: createMattersHoldsTool, From 26ef1cfc110c6eced72263e11cc7f2f8cc4f37ef Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 25 Feb 2026 14:04:46 -0800 Subject: [PATCH 5/7] lint --- apps/docs/components/ui/icon-mapping.ts | 12 ++++++------ apps/docs/content/docs/en/tools/meta.json | 2 +- apps/sim/blocks/blocks/google_bigquery.ts | 10 ++++++++-- apps/sim/lib/oauth/oauth.ts | 2 +- apps/sim/tools/google_bigquery/get_table.ts | 10 ++++++++-- apps/sim/tools/google_bigquery/insert_rows.ts | 5 ++++- apps/sim/tools/google_bigquery/query.ts | 16 +++++++++++++--- apps/sim/tools/registry.ts | 14 +++++++------- 8 files changed, 48 insertions(+), 23 deletions(-) diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index 6d132aacb2..b7e72669d6 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, GoogleBigQueryIcon, @@ -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 9a122688e8..e5afbc1b50 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/blocks/blocks/google_bigquery.ts b/apps/sim/blocks/blocks/google_bigquery.ts index 29477770f5..0ba15dfe56 100644 --- a/apps/sim/blocks/blocks/google_bigquery.ts +++ b/apps/sim/blocks/blocks/google_bigquery.ts @@ -212,13 +212,19 @@ Return ONLY the JSON array - no explanations, no wrapping, no extra text.`, query: { type: 'string', description: 'SQL query to execute' }, useLegacySql: { type: 'boolean', description: 'Whether to use legacy SQL syntax' }, maxResults: { type: 'number', description: 'Maximum number of results to return' }, - defaultDatasetId: { type: 'string', description: 'Default dataset for unqualified table names' }, + defaultDatasetId: { + type: 'string', + description: 'Default dataset for unqualified table names', + }, location: { type: 'string', description: 'Processing location' }, datasetId: { type: 'string', description: 'BigQuery dataset ID' }, tableId: { type: 'string', description: 'BigQuery table ID' }, rows: { type: 'string', description: 'JSON array of row objects to insert' }, skipInvalidRows: { type: 'boolean', description: 'Whether to skip invalid rows during insert' }, - ignoreUnknownValues: { type: 'boolean', description: 'Whether to ignore unknown column values' }, + ignoreUnknownValues: { + type: 'boolean', + description: 'Whether to ignore unknown column values', + }, pageToken: { type: 'string', description: 'Pagination token' }, }, outputs: { diff --git a/apps/sim/lib/oauth/oauth.ts b/apps/sim/lib/oauth/oauth.ts index 3f827eab0d..96d9167dbe 100644 --- a/apps/sim/lib/oauth/oauth.ts +++ b/apps/sim/lib/oauth/oauth.ts @@ -8,12 +8,12 @@ import { DropboxIcon, GithubIcon, GmailIcon, + GoogleBigQueryIcon, GoogleCalendarIcon, GoogleDocsIcon, GoogleDriveIcon, GoogleFormsIcon, GoogleGroupsIcon, - GoogleBigQueryIcon, GoogleIcon, GoogleSheetsIcon, HubspotIcon, diff --git a/apps/sim/tools/google_bigquery/get_table.ts b/apps/sim/tools/google_bigquery/get_table.ts index 29c46aa7df..eaec40a96d 100644 --- a/apps/sim/tools/google_bigquery/get_table.ts +++ b/apps/sim/tools/google_bigquery/get_table.ts @@ -96,9 +96,15 @@ export const googleBigQueryGetTableTool: ToolConfig< description: { type: 'string', description: 'Table description' }, numRows: { type: 'string', description: 'Total number of rows' }, numBytes: { type: 'string', description: 'Total size in bytes' }, - schema: { type: 'json', description: 'Array of column definitions with name, type, mode, and description' }, + schema: { + type: 'json', + description: 'Array of column definitions with name, type, mode, and description', + }, creationTime: { type: 'string', description: 'Table creation time (milliseconds since epoch)' }, - lastModifiedTime: { type: 'string', description: 'Last modification time (milliseconds since epoch)' }, + lastModifiedTime: { + type: 'string', + description: 'Last modification time (milliseconds since epoch)', + }, location: { type: 'string', description: 'Data location' }, }, } diff --git a/apps/sim/tools/google_bigquery/insert_rows.ts b/apps/sim/tools/google_bigquery/insert_rows.ts index b98c02dadf..20790faa68 100644 --- a/apps/sim/tools/google_bigquery/insert_rows.ts +++ b/apps/sim/tools/google_bigquery/insert_rows.ts @@ -136,6 +136,9 @@ export const googleBigQueryInsertRowsTool: ToolConfig< outputs: { insertedRows: { type: 'number', description: 'Number of rows successfully inserted' }, - errors: { type: 'json', description: 'Array of per-row insertion errors (empty if all succeeded)' }, + errors: { + type: 'json', + description: 'Array of per-row insertion errors (empty if all succeeded)', + }, }, } diff --git a/apps/sim/tools/google_bigquery/query.ts b/apps/sim/tools/google_bigquery/query.ts index 815c6f6651..d4c9b7b880 100644 --- a/apps/sim/tools/google_bigquery/query.ts +++ b/apps/sim/tools/google_bigquery/query.ts @@ -1,7 +1,13 @@ -import type { GoogleBigQueryQueryParams, GoogleBigQueryQueryResponse } from '@/tools/google_bigquery/types' +import type { + GoogleBigQueryQueryParams, + GoogleBigQueryQueryResponse, +} from '@/tools/google_bigquery/types' import type { ToolConfig } from '@/tools/types' -export const googleBigQueryQueryTool: ToolConfig = { +export const googleBigQueryQueryTool: ToolConfig< + GoogleBigQueryQueryParams, + GoogleBigQueryQueryResponse +> = { id: 'google_bigquery_query', name: 'BigQuery Run Query', description: 'Run a SQL query against Google BigQuery and return the results', @@ -120,7 +126,11 @@ export const googleBigQueryQueryTool: ToolConfig Date: Wed, 25 Feb 2026 19:10:36 -0800 Subject: [PATCH 6/7] improvement(bigquery): destructure tool outputs with structured array/object types --- .../content/docs/en/tools/google_bigquery.mdx | 44 ++++++++++++++----- apps/sim/tools/google_bigquery/get_table.ts | 26 ++++++----- apps/sim/tools/google_bigquery/insert_rows.ts | 20 ++++++++- .../tools/google_bigquery/list_datasets.ts | 16 ++++++- apps/sim/tools/google_bigquery/list_tables.ts | 20 +++++++-- apps/sim/tools/google_bigquery/query.ts | 32 ++++++++++---- 6 files changed, 123 insertions(+), 35 deletions(-) diff --git a/apps/docs/content/docs/en/tools/google_bigquery.mdx b/apps/docs/content/docs/en/tools/google_bigquery.mdx index e13a87a4ff..4218ff9f68 100644 --- a/apps/docs/content/docs/en/tools/google_bigquery.mdx +++ b/apps/docs/content/docs/en/tools/google_bigquery.mdx @@ -37,13 +37,16 @@ Run a SQL query against Google BigQuery and return the results | Parameter | Type | Description | | --------- | ---- | ----------- | -| `columns` | json | Array of column names from the query result | -| `rows` | json | Array of row objects with column values | -| `totalRows` | string | Total number of rows in the result | +| `columns` | array | Array of column names from the query result | +| `rows` | array | Array of row objects keyed by column name | +| `totalRows` | string | Total number of rows in the complete result set | | `jobComplete` | boolean | Whether the query completed within the timeout | | `totalBytesProcessed` | string | Total bytes processed by the query | | `cacheHit` | boolean | Whether the query result was served from cache | -| `jobReference` | json | Job reference with projectId, jobId, and location \(useful when jobComplete is false\) | +| `jobReference` | object | Job reference \(useful when jobComplete is false\) | +| ↳ `projectId` | string | Project ID containing the job | +| ↳ `jobId` | string | Unique job identifier | +| ↳ `location` | string | Geographic location of the job | | `pageToken` | string | Token for fetching additional result pages | ### `google_bigquery_list_datasets` @@ -62,7 +65,11 @@ List all datasets in a Google BigQuery project | Parameter | Type | Description | | --------- | ---- | ----------- | -| `datasets` | json | Array of dataset objects | +| `datasets` | array | Array of dataset objects | +| ↳ `datasetId` | string | Unique dataset identifier | +| ↳ `projectId` | string | Project ID containing this dataset | +| ↳ `friendlyName` | string | Descriptive name for the dataset | +| ↳ `location` | string | Geographic location where the data resides | | `nextPageToken` | string | Token for fetching next page of results | ### `google_bigquery_list_tables` @@ -82,7 +89,13 @@ List all tables in a Google BigQuery dataset | Parameter | Type | Description | | --------- | ---- | ----------- | -| `tables` | json | Array of table objects | +| `tables` | array | Array of table objects | +| ↳ `tableId` | string | Table identifier | +| ↳ `datasetId` | string | Dataset ID containing this table | +| ↳ `projectId` | string | Project ID containing this table | +| ↳ `type` | string | Table type \(TABLE, VIEW, EXTERNAL, etc.\) | +| ↳ `friendlyName` | string | User-friendly name for the table | +| ↳ `creationTime` | string | Time when created, in milliseconds since epoch | | `totalItems` | number | Total number of tables in the dataset | | `nextPageToken` | string | Token for fetching next page of results | @@ -105,14 +118,18 @@ Get metadata and schema for a Google BigQuery table | `tableId` | string | Table ID | | `datasetId` | string | Dataset ID | | `projectId` | string | Project ID | -| `type` | string | Table type \(TABLE, VIEW, etc.\) | +| `type` | string | Table type \(TABLE, VIEW, SNAPSHOT, MATERIALIZED_VIEW, EXTERNAL\) | | `description` | string | Table description | | `numRows` | string | Total number of rows | -| `numBytes` | string | Total size in bytes | -| `schema` | json | Array of column definitions with name, type, mode, and description | +| `numBytes` | string | Total size in bytes, excluding data in streaming buffer | +| `schema` | array | Array of column definitions | +| ↳ `name` | string | Column name | +| ↳ `type` | string | Data type \(STRING, INTEGER, FLOAT, BOOLEAN, TIMESTAMP, RECORD, etc.\) | +| ↳ `mode` | string | Column mode \(NULLABLE, REQUIRED, or REPEATED\) | +| ↳ `description` | string | Column description | | `creationTime` | string | Table creation time \(milliseconds since epoch\) | | `lastModifiedTime` | string | Last modification time \(milliseconds since epoch\) | -| `location` | string | Data location | +| `location` | string | Geographic location where the table resides | ### `google_bigquery_insert_rows` @@ -134,6 +151,11 @@ Insert rows into a Google BigQuery table using streaming insert | Parameter | Type | Description | | --------- | ---- | ----------- | | `insertedRows` | number | Number of rows successfully inserted | -| `errors` | json | Array of per-row insertion errors \(empty if all succeeded\) | +| `errors` | array | Array of per-row insertion errors \(empty if all succeeded\) | +| ↳ `index` | number | Zero-based index of the row that failed | +| ↳ `errors` | array | Error details for this row | +| ↳ `reason` | string | Short error code summarizing the error | +| ↳ `location` | string | Where the error occurred | +| ↳ `message` | string | Human-readable error description | diff --git a/apps/sim/tools/google_bigquery/get_table.ts b/apps/sim/tools/google_bigquery/get_table.ts index eaec40a96d..c03b612c9b 100644 --- a/apps/sim/tools/google_bigquery/get_table.ts +++ b/apps/sim/tools/google_bigquery/get_table.ts @@ -92,19 +92,25 @@ export const googleBigQueryGetTableTool: ToolConfig< tableId: { type: 'string', description: 'Table ID' }, datasetId: { type: 'string', description: 'Dataset ID' }, projectId: { type: 'string', description: 'Project ID' }, - type: { type: 'string', description: 'Table type (TABLE, VIEW, etc.)' }, - description: { type: 'string', description: 'Table description' }, + type: { type: 'string', description: 'Table type (TABLE, VIEW, SNAPSHOT, MATERIALIZED_VIEW, EXTERNAL)' }, + description: { type: 'string', description: 'Table description', optional: true }, numRows: { type: 'string', description: 'Total number of rows' }, - numBytes: { type: 'string', description: 'Total size in bytes' }, + numBytes: { type: 'string', description: 'Total size in bytes, excluding data in streaming buffer' }, schema: { - type: 'json', - description: 'Array of column definitions with name, type, mode, and description', + type: 'array', + description: 'Array of column definitions', + items: { + type: 'object', + properties: { + name: { type: 'string', description: 'Column name' }, + type: { type: 'string', description: 'Data type (STRING, INTEGER, FLOAT, BOOLEAN, TIMESTAMP, RECORD, etc.)' }, + mode: { type: 'string', description: 'Column mode (NULLABLE, REQUIRED, or REPEATED)', optional: true }, + description: { type: 'string', description: 'Column description', optional: true }, + }, + }, }, creationTime: { type: 'string', description: 'Table creation time (milliseconds since epoch)' }, - lastModifiedTime: { - type: 'string', - description: 'Last modification time (milliseconds since epoch)', - }, - location: { type: 'string', description: 'Data location' }, + lastModifiedTime: { type: 'string', description: 'Last modification time (milliseconds since epoch)' }, + location: { type: 'string', description: 'Geographic location where the table resides' }, }, } diff --git a/apps/sim/tools/google_bigquery/insert_rows.ts b/apps/sim/tools/google_bigquery/insert_rows.ts index 20790faa68..71697f66d4 100644 --- a/apps/sim/tools/google_bigquery/insert_rows.ts +++ b/apps/sim/tools/google_bigquery/insert_rows.ts @@ -137,8 +137,26 @@ export const googleBigQueryInsertRowsTool: ToolConfig< outputs: { insertedRows: { type: 'number', description: 'Number of rows successfully inserted' }, errors: { - type: 'json', + type: 'array', description: 'Array of per-row insertion errors (empty if all succeeded)', + items: { + type: 'object', + properties: { + index: { type: 'number', description: 'Zero-based index of the row that failed' }, + errors: { + type: 'array', + description: 'Error details for this row', + items: { + type: 'object', + properties: { + reason: { type: 'string', description: 'Short error code summarizing the error', optional: true }, + location: { type: 'string', description: 'Where the error occurred', optional: true }, + message: { type: 'string', description: 'Human-readable error description', optional: true }, + }, + }, + }, + }, + }, }, }, } diff --git a/apps/sim/tools/google_bigquery/list_datasets.ts b/apps/sim/tools/google_bigquery/list_datasets.ts index 8cb9629763..e9fd5fcb93 100644 --- a/apps/sim/tools/google_bigquery/list_datasets.ts +++ b/apps/sim/tools/google_bigquery/list_datasets.ts @@ -95,7 +95,19 @@ export const googleBigQueryListDatasetsTool: ToolConfig< }, outputs: { - datasets: { type: 'json', description: 'Array of dataset objects' }, - nextPageToken: { type: 'string', description: 'Token for fetching next page of results' }, + datasets: { + type: 'array', + description: 'Array of dataset objects', + items: { + type: 'object', + properties: { + datasetId: { type: 'string', description: 'Unique dataset identifier' }, + projectId: { type: 'string', description: 'Project ID containing this dataset' }, + friendlyName: { type: 'string', description: 'Descriptive name for the dataset', optional: true }, + location: { type: 'string', description: 'Geographic location where the data resides' }, + }, + }, + }, + nextPageToken: { type: 'string', description: 'Token for fetching next page of results', optional: true }, }, } diff --git a/apps/sim/tools/google_bigquery/list_tables.ts b/apps/sim/tools/google_bigquery/list_tables.ts index 1a0df9c432..b127871dda 100644 --- a/apps/sim/tools/google_bigquery/list_tables.ts +++ b/apps/sim/tools/google_bigquery/list_tables.ts @@ -105,8 +105,22 @@ export const googleBigQueryListTablesTool: ToolConfig< }, outputs: { - tables: { type: 'json', description: 'Array of table objects' }, - totalItems: { type: 'number', description: 'Total number of tables in the dataset' }, - nextPageToken: { type: 'string', description: 'Token for fetching next page of results' }, + tables: { + type: 'array', + description: 'Array of table objects', + items: { + type: 'object', + properties: { + tableId: { type: 'string', description: 'Table identifier' }, + datasetId: { type: 'string', description: 'Dataset ID containing this table' }, + projectId: { type: 'string', description: 'Project ID containing this table' }, + type: { type: 'string', description: 'Table type (TABLE, VIEW, EXTERNAL, etc.)' }, + friendlyName: { type: 'string', description: 'User-friendly name for the table', optional: true }, + creationTime: { type: 'string', description: 'Time when created, in milliseconds since epoch', optional: true }, + }, + }, + }, + totalItems: { type: 'number', description: 'Total number of tables in the dataset', optional: true }, + nextPageToken: { type: 'string', description: 'Token for fetching next page of results', optional: true }, }, } diff --git a/apps/sim/tools/google_bigquery/query.ts b/apps/sim/tools/google_bigquery/query.ts index d4c9b7b880..261996cd7f 100644 --- a/apps/sim/tools/google_bigquery/query.ts +++ b/apps/sim/tools/google_bigquery/query.ts @@ -120,17 +120,33 @@ export const googleBigQueryQueryTool: ToolConfig< }, outputs: { - columns: { type: 'json', description: 'Array of column names from the query result' }, - rows: { type: 'json', description: 'Array of row objects with column values' }, - totalRows: { type: 'string', description: 'Total number of rows in the result' }, + columns: { + type: 'array', + description: 'Array of column names from the query result', + items: { type: 'string', description: 'Column name' }, + }, + rows: { + type: 'array', + description: 'Array of row objects keyed by column name', + items: { + type: 'object', + description: 'Row with column name/value pairs', + }, + }, + totalRows: { type: 'string', description: 'Total number of rows in the complete result set', optional: true }, jobComplete: { type: 'boolean', description: 'Whether the query completed within the timeout' }, totalBytesProcessed: { type: 'string', description: 'Total bytes processed by the query' }, - cacheHit: { type: 'boolean', description: 'Whether the query result was served from cache' }, + cacheHit: { type: 'boolean', description: 'Whether the query result was served from cache', optional: true }, jobReference: { - type: 'json', - description: - 'Job reference with projectId, jobId, and location (useful when jobComplete is false)', + type: 'object', + description: 'Job reference (useful when jobComplete is false)', + optional: true, + properties: { + projectId: { type: 'string', description: 'Project ID containing the job' }, + jobId: { type: 'string', description: 'Unique job identifier' }, + location: { type: 'string', description: 'Geographic location of the job' }, + }, }, - pageToken: { type: 'string', description: 'Token for fetching additional result pages' }, + pageToken: { type: 'string', description: 'Token for fetching additional result pages', optional: true }, }, } From 5432565920cdfe5f80fc2bbb47dab8b93323de8c Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 25 Feb 2026 19:26:53 -0800 Subject: [PATCH 7/7] lint --- apps/sim/tools/google_bigquery/get_table.ts | 26 +++++++++++++++---- apps/sim/tools/google_bigquery/insert_rows.ts | 18 ++++++++++--- .../tools/google_bigquery/list_datasets.ts | 12 +++++++-- apps/sim/tools/google_bigquery/list_tables.ts | 24 ++++++++++++++--- apps/sim/tools/google_bigquery/query.ts | 18 ++++++++++--- 5 files changed, 81 insertions(+), 17 deletions(-) diff --git a/apps/sim/tools/google_bigquery/get_table.ts b/apps/sim/tools/google_bigquery/get_table.ts index c03b612c9b..50cf0437a8 100644 --- a/apps/sim/tools/google_bigquery/get_table.ts +++ b/apps/sim/tools/google_bigquery/get_table.ts @@ -92,10 +92,16 @@ export const googleBigQueryGetTableTool: ToolConfig< tableId: { type: 'string', description: 'Table ID' }, datasetId: { type: 'string', description: 'Dataset ID' }, projectId: { type: 'string', description: 'Project ID' }, - type: { type: 'string', description: 'Table type (TABLE, VIEW, SNAPSHOT, MATERIALIZED_VIEW, EXTERNAL)' }, + type: { + type: 'string', + description: 'Table type (TABLE, VIEW, SNAPSHOT, MATERIALIZED_VIEW, EXTERNAL)', + }, description: { type: 'string', description: 'Table description', optional: true }, numRows: { type: 'string', description: 'Total number of rows' }, - numBytes: { type: 'string', description: 'Total size in bytes, excluding data in streaming buffer' }, + numBytes: { + type: 'string', + description: 'Total size in bytes, excluding data in streaming buffer', + }, schema: { type: 'array', description: 'Array of column definitions', @@ -103,14 +109,24 @@ export const googleBigQueryGetTableTool: ToolConfig< type: 'object', properties: { name: { type: 'string', description: 'Column name' }, - type: { type: 'string', description: 'Data type (STRING, INTEGER, FLOAT, BOOLEAN, TIMESTAMP, RECORD, etc.)' }, - mode: { type: 'string', description: 'Column mode (NULLABLE, REQUIRED, or REPEATED)', optional: true }, + type: { + type: 'string', + description: 'Data type (STRING, INTEGER, FLOAT, BOOLEAN, TIMESTAMP, RECORD, etc.)', + }, + mode: { + type: 'string', + description: 'Column mode (NULLABLE, REQUIRED, or REPEATED)', + optional: true, + }, description: { type: 'string', description: 'Column description', optional: true }, }, }, }, creationTime: { type: 'string', description: 'Table creation time (milliseconds since epoch)' }, - lastModifiedTime: { type: 'string', description: 'Last modification time (milliseconds since epoch)' }, + lastModifiedTime: { + type: 'string', + description: 'Last modification time (milliseconds since epoch)', + }, location: { type: 'string', description: 'Geographic location where the table resides' }, }, } diff --git a/apps/sim/tools/google_bigquery/insert_rows.ts b/apps/sim/tools/google_bigquery/insert_rows.ts index 71697f66d4..8f7e03e839 100644 --- a/apps/sim/tools/google_bigquery/insert_rows.ts +++ b/apps/sim/tools/google_bigquery/insert_rows.ts @@ -149,9 +149,21 @@ export const googleBigQueryInsertRowsTool: ToolConfig< items: { type: 'object', properties: { - reason: { type: 'string', description: 'Short error code summarizing the error', optional: true }, - location: { type: 'string', description: 'Where the error occurred', optional: true }, - message: { type: 'string', description: 'Human-readable error description', optional: true }, + reason: { + type: 'string', + description: 'Short error code summarizing the error', + optional: true, + }, + location: { + type: 'string', + description: 'Where the error occurred', + optional: true, + }, + message: { + type: 'string', + description: 'Human-readable error description', + optional: true, + }, }, }, }, diff --git a/apps/sim/tools/google_bigquery/list_datasets.ts b/apps/sim/tools/google_bigquery/list_datasets.ts index e9fd5fcb93..75da30bfe5 100644 --- a/apps/sim/tools/google_bigquery/list_datasets.ts +++ b/apps/sim/tools/google_bigquery/list_datasets.ts @@ -103,11 +103,19 @@ export const googleBigQueryListDatasetsTool: ToolConfig< properties: { datasetId: { type: 'string', description: 'Unique dataset identifier' }, projectId: { type: 'string', description: 'Project ID containing this dataset' }, - friendlyName: { type: 'string', description: 'Descriptive name for the dataset', optional: true }, + friendlyName: { + type: 'string', + description: 'Descriptive name for the dataset', + optional: true, + }, location: { type: 'string', description: 'Geographic location where the data resides' }, }, }, }, - nextPageToken: { type: 'string', description: 'Token for fetching next page of results', optional: true }, + nextPageToken: { + type: 'string', + description: 'Token for fetching next page of results', + optional: true, + }, }, } diff --git a/apps/sim/tools/google_bigquery/list_tables.ts b/apps/sim/tools/google_bigquery/list_tables.ts index b127871dda..1d116a5c1e 100644 --- a/apps/sim/tools/google_bigquery/list_tables.ts +++ b/apps/sim/tools/google_bigquery/list_tables.ts @@ -115,12 +115,28 @@ export const googleBigQueryListTablesTool: ToolConfig< datasetId: { type: 'string', description: 'Dataset ID containing this table' }, projectId: { type: 'string', description: 'Project ID containing this table' }, type: { type: 'string', description: 'Table type (TABLE, VIEW, EXTERNAL, etc.)' }, - friendlyName: { type: 'string', description: 'User-friendly name for the table', optional: true }, - creationTime: { type: 'string', description: 'Time when created, in milliseconds since epoch', optional: true }, + friendlyName: { + type: 'string', + description: 'User-friendly name for the table', + optional: true, + }, + creationTime: { + type: 'string', + description: 'Time when created, in milliseconds since epoch', + optional: true, + }, }, }, }, - totalItems: { type: 'number', description: 'Total number of tables in the dataset', optional: true }, - nextPageToken: { type: 'string', description: 'Token for fetching next page of results', optional: true }, + totalItems: { + type: 'number', + description: 'Total number of tables in the dataset', + optional: true, + }, + nextPageToken: { + type: 'string', + description: 'Token for fetching next page of results', + optional: true, + }, }, } diff --git a/apps/sim/tools/google_bigquery/query.ts b/apps/sim/tools/google_bigquery/query.ts index 261996cd7f..ad11adc901 100644 --- a/apps/sim/tools/google_bigquery/query.ts +++ b/apps/sim/tools/google_bigquery/query.ts @@ -133,10 +133,18 @@ export const googleBigQueryQueryTool: ToolConfig< description: 'Row with column name/value pairs', }, }, - totalRows: { type: 'string', description: 'Total number of rows in the complete result set', optional: true }, + totalRows: { + type: 'string', + description: 'Total number of rows in the complete result set', + optional: true, + }, jobComplete: { type: 'boolean', description: 'Whether the query completed within the timeout' }, totalBytesProcessed: { type: 'string', description: 'Total bytes processed by the query' }, - cacheHit: { type: 'boolean', description: 'Whether the query result was served from cache', optional: true }, + cacheHit: { + type: 'boolean', + description: 'Whether the query result was served from cache', + optional: true, + }, jobReference: { type: 'object', description: 'Job reference (useful when jobComplete is false)', @@ -147,6 +155,10 @@ export const googleBigQueryQueryTool: ToolConfig< location: { type: 'string', description: 'Geographic location of the job' }, }, }, - pageToken: { type: 'string', description: 'Token for fetching additional result pages', optional: true }, + pageToken: { + type: 'string', + description: 'Token for fetching additional result pages', + optional: true, + }, }, }