mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-09 23:17:59 -05:00
Compare commits
9 Commits
main
...
fix/google
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3979d09892 | ||
|
|
79a93ed630 | ||
|
|
58417ebaa8 | ||
|
|
53cfd70e11 | ||
|
|
59aca33ee3 | ||
|
|
a00ec627ec | ||
|
|
1fee00aae1 | ||
|
|
3beb18b76a | ||
|
|
ff1af41b37 |
@@ -31,6 +31,9 @@ Create an export in a matter
|
||||
| `corpus` | string | Yes | Data corpus to export \(MAIL, DRIVE, GROUPS, HANGOUTS_CHAT, VOICE\) |
|
||||
| `accountEmails` | string | No | Comma-separated list of user emails to scope export |
|
||||
| `orgUnitId` | string | No | Organization unit ID to scope export \(alternative to emails\) |
|
||||
| `startTime` | string | No | Start time for date filtering \(ISO 8601 format, e.g., 2024-01-01T00:00:00Z\) |
|
||||
| `endTime` | string | No | End time for date filtering \(ISO 8601 format, e.g., 2024-12-31T23:59:59Z\) |
|
||||
| `terms` | string | No | Search query terms to filter exported content |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -91,6 +94,10 @@ Create a hold in a matter
|
||||
| `corpus` | string | Yes | Data corpus to hold \(MAIL, DRIVE, GROUPS, HANGOUTS_CHAT, VOICE\) |
|
||||
| `accountEmails` | string | No | Comma-separated list of user emails to put on hold |
|
||||
| `orgUnitId` | string | No | Organization unit ID to put on hold \(alternative to accounts\) |
|
||||
| `terms` | string | No | Search terms to filter held content \(for MAIL and GROUPS corpus\) |
|
||||
| `startTime` | string | No | Start time for date filtering \(ISO 8601 format, for MAIL and GROUPS corpus\) |
|
||||
| `endTime` | string | No | End time for date filtering \(ISO 8601 format, for MAIL and GROUPS corpus\) |
|
||||
| `includeSharedDrives` | boolean | No | Include files in shared drives \(for DRIVE corpus\) |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -159,6 +159,167 @@ Return ONLY the hold name - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Org Unit ID (alternative to emails)',
|
||||
condition: { field: 'operation', value: ['create_matters_holds', 'create_matters_export'] },
|
||||
},
|
||||
// Date filtering for exports (works with all corpus types)
|
||||
{
|
||||
id: 'startTime',
|
||||
title: 'Start Time',
|
||||
type: 'short-input',
|
||||
placeholder: 'YYYY-MM-DDTHH:mm:ssZ',
|
||||
condition: { field: 'operation', value: 'create_matters_export' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate an ISO 8601 timestamp in GMT based on the user's description for Google Vault date filtering.
|
||||
The timestamp should be in the format: YYYY-MM-DDTHH:mm:ssZ (UTC timezone).
|
||||
Note: Google Vault rounds times to 12 AM on the specified date.
|
||||
Examples:
|
||||
- "yesterday" -> Calculate yesterday's date at 00:00:00Z
|
||||
- "last week" -> Calculate 7 days ago at 00:00:00Z
|
||||
- "beginning of this month" -> Calculate the 1st of current month at 00:00:00Z
|
||||
- "January 1, 2024" -> 2024-01-01T00:00:00Z
|
||||
|
||||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the start date (e.g., "last month", "January 1, 2024")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'endTime',
|
||||
title: 'End Time',
|
||||
type: 'short-input',
|
||||
placeholder: 'YYYY-MM-DDTHH:mm:ssZ',
|
||||
condition: { field: 'operation', value: 'create_matters_export' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate an ISO 8601 timestamp in GMT based on the user's description for Google Vault date filtering.
|
||||
The timestamp should be in the format: YYYY-MM-DDTHH:mm:ssZ (UTC timezone).
|
||||
Note: Google Vault rounds times to 12 AM on the specified date.
|
||||
Examples:
|
||||
- "now" -> Current timestamp
|
||||
- "today" -> Today's date at 23:59:59Z
|
||||
- "end of last month" -> Last day of previous month at 23:59:59Z
|
||||
- "December 31, 2024" -> 2024-12-31T23:59:59Z
|
||||
|
||||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the end date (e.g., "today", "end of last quarter")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
// Date filtering for holds (only works with MAIL and GROUPS corpus)
|
||||
{
|
||||
id: 'startTime',
|
||||
title: 'Start Time',
|
||||
type: 'short-input',
|
||||
placeholder: 'YYYY-MM-DDTHH:mm:ssZ',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'create_matters_holds',
|
||||
and: { field: 'corpus', value: ['MAIL', 'GROUPS'] },
|
||||
},
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate an ISO 8601 timestamp in GMT based on the user's description for Google Vault date filtering.
|
||||
The timestamp should be in the format: YYYY-MM-DDTHH:mm:ssZ (UTC timezone).
|
||||
Note: Google Vault rounds times to 12 AM on the specified date.
|
||||
Examples:
|
||||
- "yesterday" -> Calculate yesterday's date at 00:00:00Z
|
||||
- "last week" -> Calculate 7 days ago at 00:00:00Z
|
||||
- "beginning of this month" -> Calculate the 1st of current month at 00:00:00Z
|
||||
- "January 1, 2024" -> 2024-01-01T00:00:00Z
|
||||
|
||||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the start date (e.g., "last month", "January 1, 2024")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'endTime',
|
||||
title: 'End Time',
|
||||
type: 'short-input',
|
||||
placeholder: 'YYYY-MM-DDTHH:mm:ssZ',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'create_matters_holds',
|
||||
and: { field: 'corpus', value: ['MAIL', 'GROUPS'] },
|
||||
},
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate an ISO 8601 timestamp in GMT based on the user's description for Google Vault date filtering.
|
||||
The timestamp should be in the format: YYYY-MM-DDTHH:mm:ssZ (UTC timezone).
|
||||
Note: Google Vault rounds times to 12 AM on the specified date.
|
||||
Examples:
|
||||
- "now" -> Current timestamp
|
||||
- "today" -> Today's date at 23:59:59Z
|
||||
- "end of last month" -> Last day of previous month at 23:59:59Z
|
||||
- "December 31, 2024" -> 2024-12-31T23:59:59Z
|
||||
|
||||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the end date (e.g., "today", "end of last quarter")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
// Search terms for exports (works with all corpus types)
|
||||
{
|
||||
id: 'terms',
|
||||
title: 'Search Terms',
|
||||
type: 'long-input',
|
||||
placeholder: 'Enter search query (e.g., from:user@example.com subject:confidential)',
|
||||
condition: { field: 'operation', value: 'create_matters_export' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a Google Vault search query based on the user's description.
|
||||
The query can use Gmail-style search operators for MAIL corpus:
|
||||
- from:user@example.com - emails from specific sender
|
||||
- to:user@example.com - emails to specific recipient
|
||||
- subject:keyword - emails with keyword in subject
|
||||
- has:attachment - emails with attachments
|
||||
- filename:pdf - emails with PDF attachments
|
||||
- before:YYYY/MM/DD - emails before date
|
||||
- after:YYYY/MM/DD - emails after date
|
||||
|
||||
For DRIVE corpus, use Drive search operators:
|
||||
- owner:user@example.com - files owned by user
|
||||
- type:document - specific file types
|
||||
|
||||
Return ONLY the search query - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe what content to search for...',
|
||||
},
|
||||
},
|
||||
// Search terms for holds (only works with MAIL and GROUPS corpus)
|
||||
{
|
||||
id: 'terms',
|
||||
title: 'Search Terms',
|
||||
type: 'long-input',
|
||||
placeholder: 'Enter search query (e.g., from:user@example.com subject:confidential)',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'create_matters_holds',
|
||||
and: { field: 'corpus', value: ['MAIL', 'GROUPS'] },
|
||||
},
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a Google Vault search query based on the user's description.
|
||||
The query can use Gmail-style search operators:
|
||||
- from:user@example.com - emails from specific sender
|
||||
- to:user@example.com - emails to specific recipient
|
||||
- subject:keyword - emails with keyword in subject
|
||||
- has:attachment - emails with attachments
|
||||
- filename:pdf - emails with PDF attachments
|
||||
|
||||
Return ONLY the search query - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe what content to search for...',
|
||||
},
|
||||
},
|
||||
// Drive-specific option for holds
|
||||
{
|
||||
id: 'includeSharedDrives',
|
||||
title: 'Include Shared Drives',
|
||||
type: 'switch',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'create_matters_holds',
|
||||
and: { field: 'corpus', value: 'DRIVE' },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'exportId',
|
||||
title: 'Export ID',
|
||||
@@ -296,9 +457,16 @@ Return ONLY the description text - no explanations, no quotes, no extra text.`,
|
||||
corpus: { type: 'string', description: 'Data corpus (MAIL, DRIVE, GROUPS, etc.)' },
|
||||
accountEmails: { type: 'string', description: 'Comma-separated account emails' },
|
||||
orgUnitId: { type: 'string', description: 'Organization unit ID' },
|
||||
startTime: { type: 'string', description: 'Start time for date filtering (ISO 8601 format)' },
|
||||
endTime: { type: 'string', description: 'End time for date filtering (ISO 8601 format)' },
|
||||
terms: { type: 'string', description: 'Search query terms' },
|
||||
|
||||
// Create hold inputs
|
||||
holdName: { type: 'string', description: 'Name for the hold' },
|
||||
includeSharedDrives: {
|
||||
type: 'boolean',
|
||||
description: 'Include files in shared drives (for DRIVE corpus holds)',
|
||||
},
|
||||
|
||||
// Download export file inputs
|
||||
bucketName: { type: 'string', description: 'GCS bucket name from export' },
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import type { GoogleVaultCreateMattersParams } from '@/tools/google_vault/types'
|
||||
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface GoogleVaultCreateMattersParams {
|
||||
accessToken: string
|
||||
name: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
// matters.create
|
||||
// POST https://vault.googleapis.com/v1/matters
|
||||
export const createMattersTool: ToolConfig<GoogleVaultCreateMattersParams> = {
|
||||
id: 'create_matters',
|
||||
name: 'Vault Create Matter',
|
||||
@@ -38,7 +32,8 @@ export const createMattersTool: ToolConfig<GoogleVaultCreateMattersParams> = {
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to create matter')
|
||||
const errorMessage = data.error?.message || 'Failed to create matter'
|
||||
throw new Error(enhanceGoogleVaultError(errorMessage))
|
||||
}
|
||||
return { success: true, output: { matter: data } }
|
||||
},
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { GoogleVaultCreateMattersExportParams } from '@/tools/google_vault/types'
|
||||
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
// matters.exports.create
|
||||
// POST https://vault.googleapis.com/v1/matters/{matterId}/exports
|
||||
export const createMattersExportTool: ToolConfig<GoogleVaultCreateMattersExportParams> = {
|
||||
id: 'create_matters_export',
|
||||
name: 'Vault Create Export (by Matter)',
|
||||
@@ -36,6 +35,24 @@ export const createMattersExportTool: ToolConfig<GoogleVaultCreateMattersExportP
|
||||
visibility: 'user-only',
|
||||
description: 'Organization unit ID to scope export (alternative to emails)',
|
||||
},
|
||||
startTime: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Start time for date filtering (ISO 8601 format, e.g., 2024-01-01T00:00:00Z)',
|
||||
},
|
||||
endTime: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'End time for date filtering (ISO 8601 format, e.g., 2024-12-31T23:59:59Z)',
|
||||
},
|
||||
terms: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Search query terms to filter exported content',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
@@ -46,7 +63,6 @@ export const createMattersExportTool: ToolConfig<GoogleVaultCreateMattersExportP
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
// Handle accountEmails - can be string (comma-separated) or array
|
||||
let emails: string[] = []
|
||||
if (params.accountEmails) {
|
||||
if (Array.isArray(params.accountEmails)) {
|
||||
@@ -75,7 +91,6 @@ export const createMattersExportTool: ToolConfig<GoogleVaultCreateMattersExportP
|
||||
terms: params.terms || undefined,
|
||||
startTime: params.startTime || undefined,
|
||||
endTime: params.endTime || undefined,
|
||||
timeZone: params.timeZone || undefined,
|
||||
...scope,
|
||||
}
|
||||
|
||||
@@ -89,7 +104,8 @@ export const createMattersExportTool: ToolConfig<GoogleVaultCreateMattersExportP
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to create export')
|
||||
const errorMessage = data.error?.message || 'Failed to create export'
|
||||
throw new Error(enhanceGoogleVaultError(errorMessage))
|
||||
}
|
||||
return { success: true, output: { export: data } }
|
||||
},
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { GoogleVaultCreateMattersHoldsParams } from '@/tools/google_vault/types'
|
||||
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
// matters.holds.create
|
||||
// POST https://vault.googleapis.com/v1/matters/{matterId}/holds
|
||||
export const createMattersHoldsTool: ToolConfig<GoogleVaultCreateMattersHoldsParams> = {
|
||||
id: 'create_matters_holds',
|
||||
name: 'Vault Create Hold (by Matter)',
|
||||
@@ -36,6 +35,30 @@ export const createMattersHoldsTool: ToolConfig<GoogleVaultCreateMattersHoldsPar
|
||||
visibility: 'user-only',
|
||||
description: 'Organization unit ID to put on hold (alternative to accounts)',
|
||||
},
|
||||
terms: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Search terms to filter held content (for MAIL and GROUPS corpus)',
|
||||
},
|
||||
startTime: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Start time for date filtering (ISO 8601 format, for MAIL and GROUPS corpus)',
|
||||
},
|
||||
endTime: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'End time for date filtering (ISO 8601 format, for MAIL and GROUPS corpus)',
|
||||
},
|
||||
includeSharedDrives: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Include files in shared drives (for DRIVE corpus)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
@@ -46,13 +69,11 @@ export const createMattersHoldsTool: ToolConfig<GoogleVaultCreateMattersHoldsPar
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
// Build Hold body. One of accounts or orgUnit must be provided.
|
||||
const body: any = {
|
||||
name: params.holdName,
|
||||
corpus: params.corpus,
|
||||
}
|
||||
|
||||
// Handle accountEmails - can be string (comma-separated) or array
|
||||
let emails: string[] = []
|
||||
if (params.accountEmails) {
|
||||
if (Array.isArray(params.accountEmails)) {
|
||||
@@ -66,12 +87,29 @@ export const createMattersHoldsTool: ToolConfig<GoogleVaultCreateMattersHoldsPar
|
||||
}
|
||||
|
||||
if (emails.length > 0) {
|
||||
// Google Vault expects HeldAccount objects with 'email' or 'accountId'. Use 'email' here.
|
||||
body.accounts = emails.map((email: string) => ({ email }))
|
||||
} else if (params.orgUnitId) {
|
||||
body.orgUnit = { orgUnitId: params.orgUnitId }
|
||||
}
|
||||
|
||||
if (params.corpus === 'MAIL' || params.corpus === 'GROUPS') {
|
||||
const hasQueryParams = params.terms || params.startTime || params.endTime
|
||||
if (hasQueryParams) {
|
||||
const queryObj: any = {}
|
||||
if (params.terms) queryObj.terms = params.terms
|
||||
if (params.startTime) queryObj.startTime = params.startTime
|
||||
if (params.endTime) queryObj.endTime = params.endTime
|
||||
|
||||
if (params.corpus === 'MAIL') {
|
||||
body.query = { mailQuery: queryObj }
|
||||
} else {
|
||||
body.query = { groupsQuery: queryObj }
|
||||
}
|
||||
}
|
||||
} else if (params.corpus === 'DRIVE' && params.includeSharedDrives) {
|
||||
body.query = { driveQuery: { includeSharedDriveFiles: params.includeSharedDrives } }
|
||||
}
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
@@ -79,7 +117,8 @@ export const createMattersHoldsTool: ToolConfig<GoogleVaultCreateMattersHoldsPar
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to create hold')
|
||||
const errorMessage = data.error?.message || 'Failed to create hold'
|
||||
throw new Error(enhanceGoogleVaultError(errorMessage))
|
||||
}
|
||||
return { success: true, output: { hold: data } }
|
||||
},
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import type { GoogleVaultDownloadExportFileParams } from '@/tools/google_vault/types'
|
||||
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
const logger = createLogger('GoogleVaultDownloadExportFileTool')
|
||||
|
||||
interface DownloadParams {
|
||||
accessToken: string
|
||||
matterId: string
|
||||
bucketName: string
|
||||
objectName: string
|
||||
fileName?: string
|
||||
}
|
||||
|
||||
export const downloadExportFileTool: ToolConfig<DownloadParams> = {
|
||||
export const downloadExportFileTool: ToolConfig<GoogleVaultDownloadExportFileParams> = {
|
||||
id: 'google_vault_download_export_file',
|
||||
name: 'Vault Download Export File',
|
||||
description: 'Download a single file from a Google Vault export (GCS object)',
|
||||
@@ -34,17 +25,15 @@ export const downloadExportFileTool: ToolConfig<DownloadParams> = {
|
||||
url: (params) => {
|
||||
const bucket = encodeURIComponent(params.bucketName)
|
||||
const object = encodeURIComponent(params.objectName)
|
||||
// Use GCS media endpoint directly; framework will prefetch token and inject accessToken
|
||||
return `https://storage.googleapis.com/storage/v1/b/${bucket}/o/${object}?alt=media`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
// Access token is injected by the tools framework when 'credential' is present
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response, params?: DownloadParams) => {
|
||||
transformResponse: async (response: Response, params?: GoogleVaultDownloadExportFileParams) => {
|
||||
if (!response.ok) {
|
||||
let details: any
|
||||
try {
|
||||
@@ -57,10 +46,11 @@ export const downloadExportFileTool: ToolConfig<DownloadParams> = {
|
||||
details = undefined
|
||||
}
|
||||
}
|
||||
throw new Error(details?.error || `Failed to download Vault export file (${response.status})`)
|
||||
const errorMessage =
|
||||
details?.error || `Failed to download Vault export file (${response.status})`
|
||||
throw new Error(enhanceGoogleVaultError(errorMessage))
|
||||
}
|
||||
|
||||
// Since we're just doing a HEAD request to verify access, we need to fetch the actual file
|
||||
if (!params?.accessToken || !params?.bucketName || !params?.objectName) {
|
||||
throw new Error('Missing required parameters for download')
|
||||
}
|
||||
@@ -69,7 +59,6 @@ export const downloadExportFileTool: ToolConfig<DownloadParams> = {
|
||||
const object = encodeURIComponent(params.objectName)
|
||||
const downloadUrl = `https://storage.googleapis.com/storage/v1/b/${bucket}/o/${object}?alt=media`
|
||||
|
||||
// Fetch the actual file content
|
||||
const downloadResponse = await fetch(downloadUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
@@ -79,7 +68,8 @@ export const downloadExportFileTool: ToolConfig<DownloadParams> = {
|
||||
|
||||
if (!downloadResponse.ok) {
|
||||
const errorText = await downloadResponse.text().catch(() => '')
|
||||
throw new Error(`Failed to download file: ${errorText || downloadResponse.statusText}`)
|
||||
const errorMessage = `Failed to download file: ${errorText || downloadResponse.statusText}`
|
||||
throw new Error(enhanceGoogleVaultError(errorMessage))
|
||||
}
|
||||
|
||||
const contentType = downloadResponse.headers.get('content-type') || 'application/octet-stream'
|
||||
@@ -104,7 +94,6 @@ export const downloadExportFileTool: ToolConfig<DownloadParams> = {
|
||||
}
|
||||
}
|
||||
|
||||
// Get the file as an array buffer and convert to Buffer
|
||||
const arrayBuffer = await downloadResponse.arrayBuffer()
|
||||
const buffer = Buffer.from(arrayBuffer)
|
||||
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import type { GoogleVaultListMattersParams } from '@/tools/google_vault/types'
|
||||
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface GoogleVaultListMattersParams {
|
||||
accessToken: string
|
||||
pageSize?: number
|
||||
pageToken?: string
|
||||
matterId?: string // Optional get for a specific matter
|
||||
}
|
||||
|
||||
export const listMattersTool: ToolConfig<GoogleVaultListMattersParams> = {
|
||||
id: 'list_matters',
|
||||
name: 'Vault List Matters',
|
||||
@@ -47,7 +42,8 @@ export const listMattersTool: ToolConfig<GoogleVaultListMattersParams> = {
|
||||
transformResponse: async (response: Response, params?: GoogleVaultListMattersParams) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to list matters')
|
||||
const errorMessage = data.error?.message || 'Failed to list matters'
|
||||
throw new Error(enhanceGoogleVaultError(errorMessage))
|
||||
}
|
||||
if (params?.matterId) {
|
||||
return { success: true, output: { matter: data } }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { GoogleVaultListMattersExportParams } from '@/tools/google_vault/types'
|
||||
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const listMattersExportTool: ToolConfig<GoogleVaultListMattersExportParams> = {
|
||||
@@ -42,7 +43,8 @@ export const listMattersExportTool: ToolConfig<GoogleVaultListMattersExportParam
|
||||
transformResponse: async (response: Response, params?: GoogleVaultListMattersExportParams) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to list exports')
|
||||
const errorMessage = data.error?.message || 'Failed to list exports'
|
||||
throw new Error(enhanceGoogleVaultError(errorMessage))
|
||||
}
|
||||
if (params?.exportId) {
|
||||
return { success: true, output: { export: data } }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { GoogleVaultListMattersHoldsParams } from '@/tools/google_vault/types'
|
||||
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const listMattersHoldsTool: ToolConfig<GoogleVaultListMattersHoldsParams> = {
|
||||
@@ -42,7 +43,8 @@ export const listMattersHoldsTool: ToolConfig<GoogleVaultListMattersHoldsParams>
|
||||
transformResponse: async (response: Response, params?: GoogleVaultListMattersHoldsParams) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to list holds')
|
||||
const errorMessage = data.error?.message || 'Failed to list holds'
|
||||
throw new Error(enhanceGoogleVaultError(errorMessage))
|
||||
}
|
||||
if (params?.holdId) {
|
||||
return { success: true, output: { hold: data } }
|
||||
|
||||
@@ -5,31 +5,48 @@ export interface GoogleVaultCommonParams {
|
||||
matterId: string
|
||||
}
|
||||
|
||||
// Exports
|
||||
export interface GoogleVaultCreateMattersParams {
|
||||
accessToken: string
|
||||
name: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface GoogleVaultListMattersParams {
|
||||
accessToken: string
|
||||
pageSize?: number
|
||||
pageToken?: string
|
||||
matterId?: string
|
||||
}
|
||||
|
||||
export interface GoogleVaultDownloadExportFileParams {
|
||||
accessToken: string
|
||||
matterId: string
|
||||
bucketName: string
|
||||
objectName: string
|
||||
fileName?: string
|
||||
}
|
||||
|
||||
export interface GoogleVaultCreateMattersExportParams extends GoogleVaultCommonParams {
|
||||
exportName: string
|
||||
corpus: GoogleVaultCorpus
|
||||
accountEmails?: string // Comma-separated list or array handled in the tool
|
||||
accountEmails?: string
|
||||
orgUnitId?: string
|
||||
terms?: string
|
||||
startTime?: string
|
||||
endTime?: string
|
||||
timeZone?: string
|
||||
includeSharedDrives?: boolean
|
||||
}
|
||||
|
||||
export interface GoogleVaultListMattersExportParams extends GoogleVaultCommonParams {
|
||||
pageSize?: number
|
||||
pageToken?: string
|
||||
exportId?: string // Short input to fetch a specific export
|
||||
exportId?: string
|
||||
}
|
||||
|
||||
export interface GoogleVaultListMattersExportResponse extends ToolResponse {
|
||||
output: any
|
||||
}
|
||||
|
||||
// Holds
|
||||
// Simplified: default to BASIC_HOLD by omission in requests
|
||||
export type GoogleVaultHoldView = 'BASIC_HOLD' | 'FULL_HOLD'
|
||||
|
||||
export type GoogleVaultCorpus = 'MAIL' | 'DRIVE' | 'GROUPS' | 'HANGOUTS_CHAT' | 'VOICE'
|
||||
@@ -37,14 +54,18 @@ export type GoogleVaultCorpus = 'MAIL' | 'DRIVE' | 'GROUPS' | 'HANGOUTS_CHAT' |
|
||||
export interface GoogleVaultCreateMattersHoldsParams extends GoogleVaultCommonParams {
|
||||
holdName: string
|
||||
corpus: GoogleVaultCorpus
|
||||
accountEmails?: string // Comma-separated list or array handled in the tool
|
||||
accountEmails?: string
|
||||
orgUnitId?: string
|
||||
terms?: string
|
||||
startTime?: string
|
||||
endTime?: string
|
||||
includeSharedDrives?: boolean
|
||||
}
|
||||
|
||||
export interface GoogleVaultListMattersHoldsParams extends GoogleVaultCommonParams {
|
||||
pageSize?: number
|
||||
pageToken?: string
|
||||
holdId?: string // Short input to fetch a specific hold
|
||||
holdId?: string
|
||||
}
|
||||
|
||||
export interface GoogleVaultListMattersHoldsResponse extends ToolResponse {
|
||||
|
||||
41
apps/sim/tools/google_vault/utils.ts
Normal file
41
apps/sim/tools/google_vault/utils.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Google Vault Error Enhancement Utilities
|
||||
*
|
||||
* Provides user-friendly error messages for common Google Vault authentication
|
||||
* and credential issues, particularly RAPT (reauthentication policy) errors.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Detects if an error message indicates a credential/reauthentication issue
|
||||
*/
|
||||
function isCredentialRefreshError(errorMessage: string): boolean {
|
||||
const lowerMessage = errorMessage.toLowerCase()
|
||||
return (
|
||||
lowerMessage.includes('invalid_rapt') ||
|
||||
lowerMessage.includes('reauth related error') ||
|
||||
(lowerMessage.includes('invalid_grant') && lowerMessage.includes('rapt')) ||
|
||||
lowerMessage.includes('failed to refresh token') ||
|
||||
(lowerMessage.includes('failed to fetch access token') && lowerMessage.includes('401'))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enhances Google Vault error messages with actionable guidance
|
||||
*
|
||||
* For credential/reauthentication errors (RAPT errors), provides specific
|
||||
* instructions for resolving the issue through Google Admin Console settings.
|
||||
*/
|
||||
export function enhanceGoogleVaultError(errorMessage: string): string {
|
||||
if (isCredentialRefreshError(errorMessage)) {
|
||||
return (
|
||||
`Google Vault authentication failed (likely due to reauthentication policy). ` +
|
||||
`To resolve this, try disconnecting and reconnecting your Google Vault credential ` +
|
||||
`in the Credentials settings. If the issue persists, ask your Google Workspace ` +
|
||||
`administrator to disable "Reauthentication policy" for Sim Studio in the Google ` +
|
||||
`Admin Console (Security > Access and data control > Context-Aware Access > ` +
|
||||
`Reauthentication policy), or exempt Sim Studio from reauthentication requirements. ` +
|
||||
`Learn more: https://support.google.com/a/answer/9368756`
|
||||
)
|
||||
}
|
||||
return errorMessage
|
||||
}
|
||||
Reference in New Issue
Block a user