chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,83 @@
import type { GoogleVaultAddHeldAccountsParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const addHeldAccountsTool: ToolConfig<GoogleVaultAddHeldAccountsParams> = {
id: 'google_vault_add_held_accounts',
name: 'Vault Add Held Accounts',
description: 'Add accounts to an existing hold',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
holdId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The hold ID to add accounts to (e.g., "holdId123456")',
},
accountEmails: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Comma-separated list of user emails to add to the hold (e.g., "user1@example.com, user2@example.com")',
},
},
request: {
url: (params) =>
`https://vault.googleapis.com/v1/matters/${params.matterId.trim()}/holds/${params.holdId.trim()}:addHeldAccounts`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const emails = params.accountEmails
.split(',')
.map((e) => e.trim())
.filter(Boolean)
return { emails }
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to add held accounts'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { responses: data.responses ?? [] } }
},
outputs: {
responses: {
type: 'array',
description: 'Per-account results of the add operation',
items: {
type: 'object',
properties: {
account: { type: 'json', description: 'Held account (accountId, email)' },
status: { type: 'json', description: 'Status (code, message) if the add failed' },
},
},
},
},
}
@@ -0,0 +1,83 @@
import type { GoogleVaultAddMatterPermissionsParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const addMattersPermissionsTool: ToolConfig<GoogleVaultAddMatterPermissionsParams> = {
id: 'google_vault_add_matters_permissions',
name: 'Vault Add Matter Collaborator',
description: 'Add a collaborator (or transfer ownership) to a matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
accountId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Admin SDK account ID of the user to add as a collaborator/owner',
},
role: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Permission level to grant: COLLABORATOR or OWNER',
},
sendEmails: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'Send a notification email to the added account',
},
ccMe: {
type: 'boolean',
required: false,
visibility: 'user-only',
description:
'CC the requestor on the notification email (only relevant if sendEmails is true)',
},
},
request: {
url: (params) =>
`https://vault.googleapis.com/v1/matters/${params.matterId.trim()}:addPermissions`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => ({
matterPermission: { accountId: params.accountId, role: params.role },
sendEmails: params.sendEmails,
ccMe: params.ccMe,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to add matter collaborator'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { permission: data } }
},
outputs: {
permission: { type: 'json', description: 'Created matter permission (accountId, role)' },
},
}
@@ -0,0 +1,53 @@
import type { GoogleVaultMatterActionParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const closeMattersTool: ToolConfig<GoogleVaultMatterActionParams> = {
id: 'google_vault_close_matters',
name: 'Vault Close Matter',
description: 'Close a matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID to close (e.g., "12345678901234567890")',
},
},
request: {
url: (params) => `https://vault.googleapis.com/v1/matters/${params.matterId.trim()}:close`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: () => ({}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to close matter'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { matter: data.matter ?? data } }
},
outputs: {
matter: { type: 'json', description: 'Closed matter object' },
},
}
@@ -0,0 +1,59 @@
import type { GoogleVaultCreateMattersParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const createMattersTool: ToolConfig<GoogleVaultCreateMattersParams> = {
id: 'google_vault_create_matters',
name: 'Vault Create Matter',
description: 'Create a new matter in Google Vault',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
name: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Name for the new matter',
},
description: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Optional description for the matter',
},
},
request: {
url: () => `https://vault.googleapis.com/v1/matters`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => ({ name: params.name, description: params.description }),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to create matter'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { matter: data } }
},
outputs: {
matter: { type: 'json', description: 'Created matter object' },
},
}
@@ -0,0 +1,148 @@
import type { GoogleVaultCreateMattersExportParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const createMattersExportTool: ToolConfig<GoogleVaultCreateMattersExportParams> = {
id: 'google_vault_create_matters_export',
name: 'Vault Create Export',
description: 'Create an export in a matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
exportName: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Name for the export (avoid special characters)',
},
corpus: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Data corpus to export (MAIL, DRIVE, GROUPS, HANGOUTS_CHAT, VOICE)',
},
accountEmails: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of user emails to scope export (e.g., "user1@example.com, user2@example.com")',
},
orgUnitId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Organization unit ID to scope export (e.g., "id:03ph8a2z1enx5q0", alternative to emails)',
},
startTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Start time for date filtering (ISO 8601 format, e.g., "2024-01-01T00:00:00Z")',
},
endTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'End time for date filtering (ISO 8601 format, e.g., "2024-12-31T23:59:59Z")',
},
terms: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Search query terms to filter exported content (e.g., "from:sender@example.com subject:invoice")',
},
},
request: {
url: (params) => `https://vault.googleapis.com/v1/matters/${params.matterId}/exports`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => {
let emails: string[] = []
if (params.accountEmails) {
if (Array.isArray(params.accountEmails)) {
emails = params.accountEmails
} else if (typeof params.accountEmails === 'string') {
emails = params.accountEmails
.split(',')
.map((e) => e.trim())
.filter(Boolean)
}
}
const scope =
emails.length > 0
? { accountInfo: { emails } }
: params.orgUnitId
? { orgUnitInfo: { orgUnitId: params.orgUnitId } }
: {}
const method =
emails.length > 0
? 'ACCOUNT'
: params.orgUnitId
? 'ORG_UNIT'
: params.corpus === 'MAIL'
? 'ENTIRE_ORG'
: undefined
if (!method) {
throw new Error(
`Account Emails or Org Unit ID is required to scope a ${params.corpus} export ` +
'(only MAIL exports can search the entire organization with no scope).'
)
}
const query: any = {
corpus: params.corpus,
dataScope: 'ALL_DATA',
method,
terms: params.terms || undefined,
startTime: params.startTime || undefined,
endTime: params.endTime || undefined,
...scope,
}
return {
name: params.exportName,
query,
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to create export'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { export: data } }
},
outputs: {
export: { type: 'json', description: 'Created export object' },
},
}
@@ -0,0 +1,149 @@
import type { GoogleVaultCreateMattersHoldsParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const createMattersHoldsTool: ToolConfig<GoogleVaultCreateMattersHoldsParams> = {
id: 'google_vault_create_matters_holds',
name: 'Vault Create Hold',
description: 'Create a hold in a matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
holdName: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Name for the hold',
},
corpus: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Data corpus to hold (MAIL, DRIVE, GROUPS, HANGOUTS_CHAT, VOICE)',
},
accountEmails: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of user emails to put on hold (e.g., "user1@example.com, user2@example.com")',
},
orgUnitId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Organization unit ID to put on hold (e.g., "id:03ph8a2z1enx5q0", alternative to accounts)',
},
terms: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Search terms to filter held content (e.g., "from:sender@example.com subject:invoice", for MAIL and GROUPS corpus)',
},
startTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Start time for date filtering (ISO 8601 format, e.g., "2024-01-01T00:00:00Z", for MAIL and GROUPS corpus)',
},
endTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'End time for date filtering (ISO 8601 format, e.g., "2024-12-31T23:59:59Z", for MAIL and GROUPS corpus)',
},
includeSharedDrives: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'Include files in shared drives (for DRIVE corpus)',
},
},
request: {
url: (params) => `https://vault.googleapis.com/v1/matters/${params.matterId}/holds`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: any = {
name: params.holdName,
corpus: params.corpus,
}
let emails: string[] = []
if (params.accountEmails) {
if (Array.isArray(params.accountEmails)) {
emails = params.accountEmails
} else if (typeof params.accountEmails === 'string') {
emails = params.accountEmails
.split(',')
.map((e) => e.trim())
.filter(Boolean)
}
}
if (emails.length > 0) {
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
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to create hold'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { hold: data } }
},
outputs: {
hold: { type: 'json', description: 'Created hold object' },
},
}
@@ -0,0 +1,146 @@
import type { GoogleVaultCreateSavedQueryParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const createSavedQueryTool: ToolConfig<GoogleVaultCreateSavedQueryParams> = {
id: 'google_vault_create_saved_query',
name: 'Vault Create Saved Query',
description: 'Save a reusable search query in a matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
displayName: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Name for the saved query',
},
corpus: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Data corpus to search (MAIL, DRIVE, GROUPS, HANGOUTS_CHAT, VOICE)',
},
accountEmails: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of user emails to scope the query (e.g., "user1@example.com, user2@example.com")',
},
orgUnitId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Organization unit ID to scope the query (e.g., "id:03ph8a2z1enx5q0", alternative to emails)',
},
startTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Start time for date filtering (ISO 8601 format, e.g., "2024-01-01T00:00:00Z")',
},
endTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'End time for date filtering (ISO 8601 format, e.g., "2024-12-31T23:59:59Z")',
},
terms: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search query terms (e.g., "from:sender@example.com subject:invoice")',
},
},
request: {
url: (params) =>
`https://vault.googleapis.com/v1/matters/${params.matterId.trim()}/savedQueries`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => {
let emails: string[] = []
if (params.accountEmails) {
if (Array.isArray(params.accountEmails)) {
emails = params.accountEmails
} else if (typeof params.accountEmails === 'string') {
emails = params.accountEmails
.split(',')
.map((e) => e.trim())
.filter(Boolean)
}
}
const scope =
emails.length > 0
? { accountInfo: { emails } }
: params.orgUnitId
? { orgUnitInfo: { orgUnitId: params.orgUnitId } }
: {}
const method =
emails.length > 0
? 'ACCOUNT'
: params.orgUnitId
? 'ORG_UNIT'
: params.corpus === 'MAIL'
? 'ENTIRE_ORG'
: undefined
if (!method) {
throw new Error(
`Account Emails or Org Unit ID is required to scope a ${params.corpus} saved query ` +
'(only MAIL queries can search the entire organization with no scope).'
)
}
return {
displayName: params.displayName,
query: {
corpus: params.corpus,
dataScope: 'ALL_DATA',
method,
terms: params.terms || undefined,
startTime: params.startTime || undefined,
endTime: params.endTime || undefined,
...scope,
},
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to create saved query'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { savedQuery: data } }
},
outputs: {
savedQuery: { type: 'json', description: 'Created saved query object' },
},
}
@@ -0,0 +1,52 @@
import type { GoogleVaultMatterActionParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const deleteMattersTool: ToolConfig<GoogleVaultMatterActionParams> = {
id: 'google_vault_delete_matters',
name: 'Vault Delete Matter',
description: 'Permanently delete a matter (must be closed first)',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID to delete (e.g., "12345678901234567890")',
},
},
request: {
url: (params) => `https://vault.googleapis.com/v1/matters/${params.matterId.trim()}`,
method: 'DELETE',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const data = await response.json().catch(() => ({}))
const errorMessage = data.error?.message || 'Failed to delete matter'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
const data = await response.json().catch(() => ({}))
return { success: true, output: { matter: data.matter ?? data } }
},
outputs: {
matter: { type: 'json', description: 'Deleted matter object' },
},
}
@@ -0,0 +1,58 @@
import type { GoogleVaultDeleteMattersExportParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const deleteMattersExportTool: ToolConfig<GoogleVaultDeleteMattersExportParams> = {
id: 'google_vault_delete_matters_export',
name: 'Vault Delete Export',
description: 'Delete an export from a matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
exportId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The export ID to delete (e.g., "exportId123456")',
},
},
request: {
url: (params) =>
`https://vault.googleapis.com/v1/matters/${params.matterId.trim()}/exports/${params.exportId.trim()}`,
method: 'DELETE',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const data = await response.json().catch(() => ({}))
const errorMessage = data.error?.message || 'Failed to delete export'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { success: true } }
},
outputs: {
success: { type: 'boolean', description: 'Whether the export was deleted' },
},
}
@@ -0,0 +1,58 @@
import type { GoogleVaultDeleteMattersHoldsParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const deleteMattersHoldsTool: ToolConfig<GoogleVaultDeleteMattersHoldsParams> = {
id: 'google_vault_delete_matters_holds',
name: 'Vault Delete Hold',
description: 'Delete a hold and release its covered accounts',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
holdId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The hold ID to delete (e.g., "holdId123456")',
},
},
request: {
url: (params) =>
`https://vault.googleapis.com/v1/matters/${params.matterId.trim()}/holds/${params.holdId.trim()}`,
method: 'DELETE',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const data = await response.json().catch(() => ({}))
const errorMessage = data.error?.message || 'Failed to delete hold'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { success: true } }
},
outputs: {
success: { type: 'boolean', description: 'Whether the hold was deleted' },
},
}
@@ -0,0 +1,58 @@
import type { GoogleVaultDeleteSavedQueryParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const deleteSavedQueryTool: ToolConfig<GoogleVaultDeleteSavedQueryParams> = {
id: 'google_vault_delete_saved_query',
name: 'Vault Delete Saved Query',
description: 'Delete a saved query from a matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
savedQueryId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The saved query ID to delete',
},
},
request: {
url: (params) =>
`https://vault.googleapis.com/v1/matters/${params.matterId.trim()}/savedQueries/${params.savedQueryId.trim()}`,
method: 'DELETE',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const data = await response.json().catch(() => ({}))
const errorMessage = data.error?.message || 'Failed to delete saved query'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { success: true } }
},
outputs: {
success: { type: 'boolean', description: 'Whether the saved query was deleted' },
},
}
@@ -0,0 +1,66 @@
import type { GoogleVaultDownloadExportFileParams } from '@/tools/google_vault/types'
import type { ToolConfig } from '@/tools/types'
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)',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
bucketName: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'GCS bucket name from cloudStorageSink.files.bucketName',
},
objectName: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'GCS object name from cloudStorageSink.files.objectName',
},
fileName: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Optional filename override for the downloaded file',
},
},
request: {
url: '/api/tools/google_vault/download-export-file',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
matterId: params.matterId,
bucketName: params.bucketName,
objectName: params.objectName,
fileName: params.fileName,
}),
},
outputs: {
file: { type: 'file', description: 'Downloaded Vault export file stored in execution files' },
},
}
+22
View File
@@ -0,0 +1,22 @@
export { addHeldAccountsTool } from '@/tools/google_vault/add_held_accounts'
export { addMattersPermissionsTool } from '@/tools/google_vault/add_matters_permissions'
export { closeMattersTool } from '@/tools/google_vault/close_matters'
export { createMattersTool } from '@/tools/google_vault/create_matters'
export { createMattersExportTool } from '@/tools/google_vault/create_matters_export'
export { createMattersHoldsTool } from '@/tools/google_vault/create_matters_holds'
export { createSavedQueryTool } from '@/tools/google_vault/create_saved_query'
export { deleteMattersTool } from '@/tools/google_vault/delete_matters'
export { deleteMattersExportTool } from '@/tools/google_vault/delete_matters_export'
export { deleteMattersHoldsTool } from '@/tools/google_vault/delete_matters_holds'
export { deleteSavedQueryTool } from '@/tools/google_vault/delete_saved_query'
export { downloadExportFileTool } from '@/tools/google_vault/download_export_file'
export { listMattersTool } from '@/tools/google_vault/list_matters'
export { listMattersExportTool } from '@/tools/google_vault/list_matters_export'
export { listMattersHoldsTool } from '@/tools/google_vault/list_matters_holds'
export { listSavedQueriesTool } from '@/tools/google_vault/list_saved_queries'
export { removeHeldAccountsTool } from '@/tools/google_vault/remove_held_accounts'
export { removeMattersPermissionsTool } from '@/tools/google_vault/remove_matters_permissions'
export { reopenMattersTool } from '@/tools/google_vault/reopen_matters'
export { undeleteMattersTool } from '@/tools/google_vault/undelete_matters'
export { updateMattersTool } from '@/tools/google_vault/update_matters'
export { updateMattersHoldsTool } from '@/tools/google_vault/update_matters_holds'
@@ -0,0 +1,79 @@
import type { GoogleVaultListMattersParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const listMattersTool: ToolConfig<GoogleVaultListMattersParams> = {
id: 'google_vault_list_matters',
name: 'Vault List Matters',
description: 'List matters, or get a specific matter if matterId is provided',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Number of matters to return per page',
},
pageToken: {
type: 'string',
required: false,
visibility: 'hidden',
description: 'Token for pagination',
},
matterId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional matter ID to fetch a specific matter (e.g., "12345678901234567890")',
},
},
request: {
url: (params) => {
if (params.matterId) {
return `https://vault.googleapis.com/v1/matters/${params.matterId}`
}
const url = new URL('https://vault.googleapis.com/v1/matters')
if (params.pageSize !== undefined && params.pageSize !== null) {
const pageSize = Number(params.pageSize)
if (Number.isFinite(pageSize) && pageSize > 0) {
url.searchParams.set('pageSize', String(pageSize))
}
}
if (params.pageToken) url.searchParams.set('pageToken', params.pageToken)
return url.toString()
},
method: 'GET',
headers: (params) => ({ Authorization: `Bearer ${params.accessToken}` }),
},
transformResponse: async (response: Response, params?: GoogleVaultListMattersParams) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to list matters'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
if (params?.matterId) {
return { success: true, output: { matter: data } }
}
return { success: true, output: data }
},
outputs: {
matters: { type: 'json', description: 'Array of matter objects' },
matter: { type: 'json', description: 'Single matter object (when matterId is provided)' },
nextPageToken: { type: 'string', description: 'Token for fetching next page of results' },
},
}
@@ -0,0 +1,85 @@
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> = {
id: 'google_vault_list_matters_export',
name: 'Vault List Exports',
description: 'List exports for a matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Number of exports to return per page',
},
pageToken: {
type: 'string',
required: false,
visibility: 'hidden',
description: 'Token for pagination',
},
exportId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional export ID to fetch a specific export (e.g., "exportId123456")',
},
},
request: {
url: (params) => {
if (params.exportId) {
return `https://vault.googleapis.com/v1/matters/${params.matterId}/exports/${params.exportId}`
}
const url = new URL(`https://vault.googleapis.com/v1/matters/${params.matterId}/exports`)
if (params.pageSize !== undefined && params.pageSize !== null) {
const pageSize = Number(params.pageSize)
if (Number.isFinite(pageSize) && pageSize > 0) {
url.searchParams.set('pageSize', String(pageSize))
}
}
if (params.pageToken) url.searchParams.set('pageToken', params.pageToken)
return url.toString()
},
method: 'GET',
headers: (params) => ({ Authorization: `Bearer ${params.accessToken}` }),
},
transformResponse: async (response: Response, params?: GoogleVaultListMattersExportParams) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to list exports'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
if (params?.exportId) {
return { success: true, output: { export: data } }
}
return { success: true, output: data }
},
outputs: {
exports: { type: 'json', description: 'Array of export objects' },
export: { type: 'json', description: 'Single export object (when exportId is provided)' },
nextPageToken: { type: 'string', description: 'Token for fetching next page of results' },
},
}
@@ -0,0 +1,85 @@
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> = {
id: 'google_vault_list_matters_holds',
name: 'Vault List Holds',
description: 'List holds for a matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Number of holds to return per page',
},
pageToken: {
type: 'string',
required: false,
visibility: 'hidden',
description: 'Token for pagination',
},
holdId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional hold ID to fetch a specific hold (e.g., "holdId123456")',
},
},
request: {
url: (params) => {
if (params.holdId) {
return `https://vault.googleapis.com/v1/matters/${params.matterId}/holds/${params.holdId}`
}
const url = new URL(`https://vault.googleapis.com/v1/matters/${params.matterId}/holds`)
if (params.pageSize !== undefined && params.pageSize !== null) {
const pageSize = Number(params.pageSize)
if (Number.isFinite(pageSize) && pageSize > 0) {
url.searchParams.set('pageSize', String(pageSize))
}
}
if (params.pageToken) url.searchParams.set('pageToken', params.pageToken)
return url.toString()
},
method: 'GET',
headers: (params) => ({ Authorization: `Bearer ${params.accessToken}` }),
},
transformResponse: async (response: Response, params?: GoogleVaultListMattersHoldsParams) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to list holds'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
if (params?.holdId) {
return { success: true, output: { hold: data } }
}
return { success: true, output: data }
},
outputs: {
holds: { type: 'json', description: 'Array of hold objects' },
hold: { type: 'json', description: 'Single hold object (when holdId is provided)' },
nextPageToken: { type: 'string', description: 'Token for fetching next page of results' },
},
}
@@ -0,0 +1,90 @@
import type { GoogleVaultListSavedQueriesParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const listSavedQueriesTool: ToolConfig<GoogleVaultListSavedQueriesParams> = {
id: 'google_vault_list_saved_queries',
name: 'Vault List Saved Queries',
description: 'List saved queries in a matter, or get a specific one if savedQueryId is provided',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Number of saved queries to return per page',
},
pageToken: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Token for pagination',
},
savedQueryId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional saved query ID to fetch a specific saved query',
},
},
request: {
url: (params) => {
if (params.savedQueryId) {
return `https://vault.googleapis.com/v1/matters/${params.matterId.trim()}/savedQueries/${params.savedQueryId.trim()}`
}
const url = new URL(
`https://vault.googleapis.com/v1/matters/${params.matterId.trim()}/savedQueries`
)
if (params.pageSize !== undefined && params.pageSize !== null) {
const pageSize = Number(params.pageSize)
if (Number.isFinite(pageSize) && pageSize > 0) {
url.searchParams.set('pageSize', String(pageSize))
}
}
if (params.pageToken) url.searchParams.set('pageToken', params.pageToken)
return url.toString()
},
method: 'GET',
headers: (params) => ({ Authorization: `Bearer ${params.accessToken}` }),
},
transformResponse: async (response: Response, params?: GoogleVaultListSavedQueriesParams) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to list saved queries'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
if (params?.savedQueryId) {
return { success: true, output: { savedQuery: data } }
}
return { success: true, output: data }
},
outputs: {
savedQueries: { type: 'json', description: 'Array of saved query objects' },
savedQuery: {
type: 'json',
description: 'Single saved query object (when savedQueryId is provided)',
},
nextPageToken: { type: 'string', description: 'Token for fetching next page of results' },
},
}
@@ -0,0 +1,80 @@
import type { GoogleVaultRemoveHeldAccountsParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const removeHeldAccountsTool: ToolConfig<GoogleVaultRemoveHeldAccountsParams> = {
id: 'google_vault_remove_held_accounts',
name: 'Vault Remove Held Accounts',
description: 'Remove accounts from an existing hold',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
holdId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The hold ID to remove accounts from (e.g., "holdId123456")',
},
accountIds: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Comma-separated list of Admin SDK account IDs to remove from the hold (e.g., "accountId1, accountId2")',
},
},
request: {
url: (params) =>
`https://vault.googleapis.com/v1/matters/${params.matterId.trim()}/holds/${params.holdId.trim()}:removeHeldAccounts`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const accountIds = params.accountIds
.split(',')
.map((id) => id.trim())
.filter(Boolean)
return { accountIds }
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to remove held accounts'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { statuses: data.statuses ?? [] } }
},
outputs: {
statuses: {
type: 'array',
description: 'Per-account removal status, in request order',
items: {
type: 'json',
description: 'Status (code, message) for one account removal',
},
},
},
}
@@ -0,0 +1,60 @@
import type { GoogleVaultRemoveMatterPermissionsParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const removeMattersPermissionsTool: ToolConfig<GoogleVaultRemoveMatterPermissionsParams> = {
id: 'google_vault_remove_matters_permissions',
name: 'Vault Remove Matter Collaborator',
description: 'Remove a collaborator from a matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
accountId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Admin SDK account ID of the collaborator to remove',
},
},
request: {
url: (params) =>
`https://vault.googleapis.com/v1/matters/${params.matterId.trim()}:removePermissions`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => ({ accountId: params.accountId }),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const data = await response.json().catch(() => ({}))
const errorMessage = data.error?.message || 'Failed to remove matter collaborator'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { success: true } }
},
outputs: {
success: { type: 'boolean', description: 'Whether the collaborator was removed' },
},
}
@@ -0,0 +1,53 @@
import type { GoogleVaultMatterActionParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const reopenMattersTool: ToolConfig<GoogleVaultMatterActionParams> = {
id: 'google_vault_reopen_matters',
name: 'Vault Reopen Matter',
description: 'Reopen a closed matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID to reopen (e.g., "12345678901234567890")',
},
},
request: {
url: (params) => `https://vault.googleapis.com/v1/matters/${params.matterId.trim()}:reopen`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: () => ({}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to reopen matter'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { matter: data.matter ?? data } }
},
outputs: {
matter: { type: 'json', description: 'Reopened matter object' },
},
}
+152
View File
@@ -0,0 +1,152 @@
import type { ToolResponse } from '@/tools/types'
interface GoogleVaultCommonParams {
accessToken: string
matterId: string
}
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
orgUnitId?: string
terms?: string
startTime?: string
endTime?: string
includeSharedDrives?: boolean
}
export interface GoogleVaultListMattersExportParams extends GoogleVaultCommonParams {
pageSize?: number
pageToken?: string
exportId?: string
}
interface GoogleVaultListMattersExportResponse extends ToolResponse {
output: any
}
export type GoogleVaultHoldView = 'BASIC_HOLD' | 'FULL_HOLD'
export type GoogleVaultCorpus = 'MAIL' | 'DRIVE' | 'GROUPS' | 'HANGOUTS_CHAT' | 'VOICE'
export interface GoogleVaultCreateMattersHoldsParams extends GoogleVaultCommonParams {
holdName: string
corpus: GoogleVaultCorpus
accountEmails?: string
orgUnitId?: string
terms?: string
startTime?: string
endTime?: string
includeSharedDrives?: boolean
}
export interface GoogleVaultListMattersHoldsParams extends GoogleVaultCommonParams {
pageSize?: number
pageToken?: string
holdId?: string
}
export interface GoogleVaultUpdateMatterParams {
accessToken: string
matterId: string
name: string
description?: string
}
export interface GoogleVaultMatterActionParams {
accessToken: string
matterId: string
}
export interface GoogleVaultAddMatterPermissionsParams {
accessToken: string
matterId: string
accountId: string
role: 'COLLABORATOR' | 'OWNER'
sendEmails?: boolean
ccMe?: boolean
}
export interface GoogleVaultRemoveMatterPermissionsParams {
accessToken: string
matterId: string
accountId: string
}
export interface GoogleVaultDeleteMattersExportParams {
accessToken: string
matterId: string
exportId: string
}
export interface GoogleVaultUpdateMattersHoldsParams extends GoogleVaultCommonParams {
holdId: string
holdName: string
corpus: GoogleVaultCorpus
accountEmails?: string
orgUnitId?: string
terms?: string
startTime?: string
endTime?: string
includeSharedDrives?: boolean
}
export interface GoogleVaultDeleteMattersHoldsParams extends GoogleVaultCommonParams {
holdId: string
}
export interface GoogleVaultAddHeldAccountsParams extends GoogleVaultCommonParams {
holdId: string
accountEmails: string
}
export interface GoogleVaultRemoveHeldAccountsParams extends GoogleVaultCommonParams {
holdId: string
accountIds: string
}
export interface GoogleVaultCreateSavedQueryParams extends GoogleVaultCommonParams {
displayName: string
corpus: GoogleVaultCorpus
accountEmails?: string
orgUnitId?: string
terms?: string
startTime?: string
endTime?: string
}
export interface GoogleVaultListSavedQueriesParams extends GoogleVaultCommonParams {
pageSize?: number
pageToken?: string
savedQueryId?: string
}
export interface GoogleVaultDeleteSavedQueryParams extends GoogleVaultCommonParams {
savedQueryId: string
}
interface GoogleVaultListMattersHoldsResponse extends ToolResponse {
output: any
}
@@ -0,0 +1,53 @@
import type { GoogleVaultMatterActionParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const undeleteMattersTool: ToolConfig<GoogleVaultMatterActionParams> = {
id: 'google_vault_undelete_matters',
name: 'Vault Undelete Matter',
description: 'Restore a deleted matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID to restore (e.g., "12345678901234567890")',
},
},
request: {
url: (params) => `https://vault.googleapis.com/v1/matters/${params.matterId.trim()}:undelete`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: () => ({}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to restore matter'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { matter: data.matter ?? data } }
},
outputs: {
matter: { type: 'json', description: 'Restored matter object' },
},
}
@@ -0,0 +1,65 @@
import type { GoogleVaultUpdateMatterParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const updateMattersTool: ToolConfig<GoogleVaultUpdateMatterParams> = {
id: 'google_vault_update_matters',
name: 'Vault Update Matter',
description: 'Update the name and/or description of a matter',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID to update (e.g., "12345678901234567890")',
},
name: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'New name for the matter',
},
description: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'New description for the matter',
},
},
request: {
url: (params) => `https://vault.googleapis.com/v1/matters/${params.matterId.trim()}`,
method: 'PUT',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => ({ name: params.name, description: params.description }),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to update matter'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { matter: data } }
},
outputs: {
matter: { type: 'json', description: 'Updated matter object' },
},
}
@@ -0,0 +1,164 @@
import type { GoogleVaultUpdateMattersHoldsParams } from '@/tools/google_vault/types'
import { enhanceGoogleVaultError } from '@/tools/google_vault/utils'
import type { ToolConfig } from '@/tools/types'
export const updateMattersHoldsTool: ToolConfig<GoogleVaultUpdateMattersHoldsParams> = {
id: 'google_vault_update_matters_holds',
name: 'Vault Update Hold',
description:
'Replace the name, query, and scope of an existing hold. This is a full-resource update: fetch the current hold first (Vault List Holds) and resupply every field you want to keep — any field left blank is cleared, not left unchanged.',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-vault',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token',
},
matterId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The matter ID (e.g., "12345678901234567890")',
},
holdId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The hold ID to update (e.g., "holdId123456")',
},
holdName: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Name for the hold',
},
corpus: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Data corpus of the hold (MAIL, DRIVE, GROUPS, HANGOUTS_CHAT, VOICE)',
},
accountEmails: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of user emails covered by the hold (e.g., "user1@example.com, user2@example.com")',
},
orgUnitId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Organization unit ID covered by the hold (e.g., "id:03ph8a2z1enx5q0", alternative to accounts)',
},
terms: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Search terms to filter held content (e.g., "from:sender@example.com subject:invoice", for MAIL and GROUPS corpus). Resupply the hold\'s current terms to keep them — this replaces the hold, so leaving it blank clears any existing filter.',
},
startTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Start time for date filtering (ISO 8601 format, e.g., "2024-01-01T00:00:00Z", for MAIL and GROUPS corpus). Resupply the hold\'s current value to keep it — leaving it blank clears any existing date filter.',
},
endTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'End time for date filtering (ISO 8601 format, e.g., "2024-12-31T23:59:59Z", for MAIL and GROUPS corpus). Resupply the hold\'s current value to keep it — leaving it blank clears any existing date filter.',
},
includeSharedDrives: {
type: 'boolean',
required: false,
visibility: 'user-only',
description:
'Include files in shared drives (for DRIVE corpus). Resupply true if the hold currently includes shared drives — leaving it false/blank clears that setting.',
},
},
request: {
url: (params) =>
`https://vault.googleapis.com/v1/matters/${params.matterId.trim()}/holds/${params.holdId.trim()}`,
method: 'PUT',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: any = {
name: params.holdName,
corpus: params.corpus,
}
let emails: string[] = []
if (params.accountEmails) {
if (Array.isArray(params.accountEmails)) {
emails = params.accountEmails
} else if (typeof params.accountEmails === 'string') {
emails = params.accountEmails
.split(',')
.map((e) => e.trim())
.filter(Boolean)
}
}
if (emails.length > 0) {
body.accounts = emails.map((email: string) => ({ email }))
} else if (params.orgUnitId) {
body.orgUnit = { orgUnitId: params.orgUnitId }
} else {
throw new Error(
'Updating a hold replaces its full scope: re-provide the current Account Emails or Org Unit ID ' +
'(they are not preserved automatically). To add or remove individual custodians without ' +
'resending the full scope, use Add Held Accounts / Remove Held Accounts instead.'
)
}
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
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
const errorMessage = data.error?.message || 'Failed to update hold'
throw new Error(enhanceGoogleVaultError(errorMessage))
}
return { success: true, output: { hold: data } }
},
outputs: {
hold: { type: 'json', description: 'Updated hold object' },
},
}
+41
View 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
}