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
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:
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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