mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-09 15:07:55 -05:00
fix(tools): fixed tool outputs (#2325)
* fix for asana and apify * fixed onedrive * fixed confluence error throwing and added upload file * fixed google vault tag dropdown and output * fix google group tag dropdown, var reference * fixed hubspot output * fixed pipedrive output * removed comments * removed more comments * consolidated file utils * fixed hubspot json schema * fix hubspot search tools * minor change
This commit is contained in:
@@ -54,7 +54,6 @@ Führe einen APIFY-Aktor synchron aus und erhalte Ergebnisse (maximal 5 Minuten)
|
||||
| `success` | boolean | Ob die Aktor-Ausführung erfolgreich war |
|
||||
| `runId` | string | APIFY-Ausführungs-ID |
|
||||
| `status` | string | Ausführungsstatus \(SUCCEEDED, FAILED, usw.\) |
|
||||
| `datasetId` | string | Dataset-ID mit Ergebnissen |
|
||||
| `items` | array | Dataset-Elemente \(falls abgeschlossen\) |
|
||||
|
||||
### `apify_run_actor_async`
|
||||
|
||||
@@ -57,7 +57,6 @@ Run an APIFY actor synchronously and get results (max 5 minutes)
|
||||
| `success` | boolean | Whether the actor run succeeded |
|
||||
| `runId` | string | APIFY run ID |
|
||||
| `status` | string | Run status \(SUCCEEDED, FAILED, etc.\) |
|
||||
| `datasetId` | string | Dataset ID containing results |
|
||||
| `items` | array | Dataset items \(if completed\) |
|
||||
|
||||
### `apify_run_actor_async`
|
||||
|
||||
@@ -54,7 +54,6 @@ Ejecuta un actor de APIFY de forma sincrónica y obtén resultados (máximo 5 mi
|
||||
| `success` | boolean | Si la ejecución del actor tuvo éxito |
|
||||
| `runId` | string | ID de ejecución de APIFY |
|
||||
| `status` | string | Estado de la ejecución \(SUCCEEDED, FAILED, etc.\) |
|
||||
| `datasetId` | string | ID del conjunto de datos que contiene los resultados |
|
||||
| `items` | array | Elementos del conjunto de datos \(si se completó\) |
|
||||
|
||||
### `apify_run_actor_async`
|
||||
|
||||
@@ -54,7 +54,6 @@ Exécuter un acteur APIFY de manière synchrone et obtenir les résultats (maxim
|
||||
| `success` | booléen | Indique si l'exécution de l'acteur a réussi |
|
||||
| `runId` | chaîne | ID d'exécution APIFY |
|
||||
| `status` | chaîne | Statut d'exécution \(SUCCEEDED, FAILED, etc.\) |
|
||||
| `datasetId` | chaîne | ID du jeu de données contenant les résultats |
|
||||
| `items` | tableau | Éléments du jeu de données \(si terminé\) |
|
||||
|
||||
### `apify_run_actor_async`
|
||||
|
||||
@@ -54,7 +54,6 @@ APIPYアクターを同期的に実行して結果を取得(最大5分)
|
||||
| `success` | boolean | アクター実行が成功したかどうか |
|
||||
| `runId` | string | APIFY実行ID |
|
||||
| `status` | string | 実行ステータス(SUCCEEDED、FAILEDなど) |
|
||||
| `datasetId` | string | 結果を含むデータセットID |
|
||||
| `items` | array | データセット項目(完了した場合) |
|
||||
|
||||
### `apify_run_actor_async`
|
||||
|
||||
@@ -54,7 +54,6 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
| `success` | boolean | actor 运行是否成功 |
|
||||
| `runId` | string | APIFY 运行 ID |
|
||||
| `status` | string | 运行状态 \(SUCCEEDED, FAILED 等\) |
|
||||
| `datasetId` | string | 包含结果的数据集 ID |
|
||||
| `items` | array | 数据集条目 \(如果已完成\) |
|
||||
|
||||
### `apify_run_actor_async`
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
extractCleanFilename,
|
||||
extractStorageKey,
|
||||
extractWorkspaceIdFromExecutionKey,
|
||||
getMimeTypeFromExtension,
|
||||
getViewerUrl,
|
||||
inferContextFromKey,
|
||||
} from '@/lib/uploads/utils/file-utils'
|
||||
@@ -44,36 +45,6 @@ interface ParseResult {
|
||||
}
|
||||
}
|
||||
|
||||
const fileTypeMap: Record<string, string> = {
|
||||
// Text formats
|
||||
txt: 'text/plain',
|
||||
csv: 'text/csv',
|
||||
json: 'application/json',
|
||||
xml: 'application/xml',
|
||||
md: 'text/markdown',
|
||||
html: 'text/html',
|
||||
css: 'text/css',
|
||||
js: 'application/javascript',
|
||||
ts: 'application/typescript',
|
||||
// Document formats
|
||||
pdf: 'application/pdf',
|
||||
doc: 'application/msword',
|
||||
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
// Spreadsheet formats
|
||||
xls: 'application/vnd.ms-excel',
|
||||
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
// Presentation formats
|
||||
ppt: 'application/vnd.ms-powerpoint',
|
||||
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
// Image formats
|
||||
png: 'image/png',
|
||||
jpg: 'image/jpeg',
|
||||
jpeg: 'image/jpeg',
|
||||
gif: 'image/gif',
|
||||
// Archive formats
|
||||
zip: 'application/zip',
|
||||
}
|
||||
|
||||
/**
|
||||
* Main API route handler
|
||||
*/
|
||||
@@ -382,7 +353,8 @@ async function handleExternalUrl(
|
||||
})
|
||||
} else {
|
||||
const { uploadWorkspaceFile } = await import('@/lib/uploads/contexts/workspace')
|
||||
const mimeType = response.headers.get('content-type') || getMimeType(extension)
|
||||
const mimeType =
|
||||
response.headers.get('content-type') || getMimeTypeFromExtension(extension)
|
||||
await uploadWorkspaceFile(workspaceId, userId, buffer, filename, mimeType)
|
||||
logger.info(`Saved URL file to workspace storage: ${filename}`)
|
||||
}
|
||||
@@ -574,7 +546,7 @@ async function handleLocalFile(
|
||||
content: result.content,
|
||||
filePath,
|
||||
metadata: {
|
||||
fileType: fileType || getMimeType(extension),
|
||||
fileType: fileType || getMimeTypeFromExtension(extension),
|
||||
size: stats.size,
|
||||
hash,
|
||||
processingTime: 0,
|
||||
@@ -709,7 +681,7 @@ async function handleGenericTextBuffer(
|
||||
content: result.content,
|
||||
filePath: originalPath || filename,
|
||||
metadata: {
|
||||
fileType: fileType || getMimeType(extension),
|
||||
fileType: fileType || getMimeTypeFromExtension(extension),
|
||||
size: fileBuffer.length,
|
||||
hash: createHash('md5').update(fileBuffer).digest('hex'),
|
||||
processingTime: 0,
|
||||
@@ -727,7 +699,7 @@ async function handleGenericTextBuffer(
|
||||
content,
|
||||
filePath: originalPath || filename,
|
||||
metadata: {
|
||||
fileType: fileType || getMimeType(extension),
|
||||
fileType: fileType || getMimeTypeFromExtension(extension),
|
||||
size: fileBuffer.length,
|
||||
hash: createHash('md5').update(fileBuffer).digest('hex'),
|
||||
processingTime: 0,
|
||||
@@ -768,7 +740,7 @@ function handleGenericBuffer(
|
||||
content,
|
||||
filePath: filename,
|
||||
metadata: {
|
||||
fileType: fileType || getMimeType(extension),
|
||||
fileType: fileType || getMimeTypeFromExtension(extension),
|
||||
size: fileBuffer.length,
|
||||
hash: createHash('md5').update(fileBuffer).digest('hex'),
|
||||
processingTime: 0,
|
||||
@@ -791,13 +763,6 @@ async function parseBufferAsPdf(buffer: Buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MIME type from file extension
|
||||
*/
|
||||
function getMimeType(extension: string): string {
|
||||
return fileTypeMap[extension] || 'application/octet-stream'
|
||||
}
|
||||
|
||||
/**
|
||||
* Format bytes to human readable size
|
||||
*/
|
||||
|
||||
@@ -86,18 +86,16 @@ export async function POST(request: Request) {
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
gid: story.gid,
|
||||
text: story.text || '',
|
||||
created_at: story.created_at,
|
||||
created_by: story.created_by
|
||||
? {
|
||||
gid: story.created_by.gid,
|
||||
name: story.created_by.name,
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
ts: new Date().toISOString(),
|
||||
gid: story.gid,
|
||||
text: story.text || '',
|
||||
created_at: story.created_at,
|
||||
created_by: story.created_by
|
||||
? {
|
||||
gid: story.created_by.gid,
|
||||
name: story.created_by.name,
|
||||
}
|
||||
: undefined,
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error processing request:', error)
|
||||
|
||||
@@ -99,15 +99,13 @@ export async function POST(request: Request) {
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
gid: task.gid,
|
||||
name: task.name,
|
||||
notes: task.notes || '',
|
||||
completed: task.completed || false,
|
||||
created_at: task.created_at,
|
||||
permalink_url: task.permalink_url,
|
||||
},
|
||||
ts: new Date().toISOString(),
|
||||
gid: task.gid,
|
||||
name: task.name,
|
||||
notes: task.notes || '',
|
||||
completed: task.completed || false,
|
||||
created_at: task.created_at,
|
||||
permalink_url: task.permalink_url,
|
||||
})
|
||||
} catch (error: any) {
|
||||
logger.error('Error creating Asana task:', {
|
||||
|
||||
@@ -73,14 +73,12 @@ export async function POST(request: Request) {
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
projects: projects.map((project: any) => ({
|
||||
gid: project.gid,
|
||||
name: project.name,
|
||||
resource_type: project.resource_type,
|
||||
})),
|
||||
},
|
||||
ts: new Date().toISOString(),
|
||||
projects: projects.map((project: any) => ({
|
||||
gid: project.gid,
|
||||
name: project.name,
|
||||
resource_type: project.resource_type,
|
||||
})),
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error processing request:', error)
|
||||
|
||||
@@ -69,31 +69,29 @@ export async function POST(request: Request) {
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
gid: task.gid,
|
||||
resource_type: task.resource_type,
|
||||
resource_subtype: task.resource_subtype,
|
||||
name: task.name,
|
||||
notes: task.notes || '',
|
||||
completed: task.completed || false,
|
||||
assignee: task.assignee
|
||||
? {
|
||||
gid: task.assignee.gid,
|
||||
name: task.assignee.name,
|
||||
}
|
||||
: undefined,
|
||||
created_by: task.created_by
|
||||
? {
|
||||
gid: task.created_by.gid,
|
||||
resource_type: task.created_by.resource_type,
|
||||
name: task.created_by.name,
|
||||
}
|
||||
: undefined,
|
||||
due_on: task.due_on || undefined,
|
||||
created_at: task.created_at,
|
||||
modified_at: task.modified_at,
|
||||
},
|
||||
ts: new Date().toISOString(),
|
||||
gid: task.gid,
|
||||
resource_type: task.resource_type,
|
||||
resource_subtype: task.resource_subtype,
|
||||
name: task.name,
|
||||
notes: task.notes || '',
|
||||
completed: task.completed || false,
|
||||
assignee: task.assignee
|
||||
? {
|
||||
gid: task.assignee.gid,
|
||||
name: task.assignee.name,
|
||||
}
|
||||
: undefined,
|
||||
created_by: task.created_by
|
||||
? {
|
||||
gid: task.created_by.gid,
|
||||
resource_type: task.created_by.resource_type,
|
||||
name: task.created_by.name,
|
||||
}
|
||||
: undefined,
|
||||
due_on: task.due_on || undefined,
|
||||
created_at: task.created_at,
|
||||
modified_at: task.modified_at,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -180,34 +178,32 @@ export async function POST(request: Request) {
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
tasks: tasks.map((task: any) => ({
|
||||
gid: task.gid,
|
||||
resource_type: task.resource_type,
|
||||
resource_subtype: task.resource_subtype,
|
||||
name: task.name,
|
||||
notes: task.notes || '',
|
||||
completed: task.completed || false,
|
||||
assignee: task.assignee
|
||||
? {
|
||||
gid: task.assignee.gid,
|
||||
name: task.assignee.name,
|
||||
}
|
||||
: undefined,
|
||||
created_by: task.created_by
|
||||
? {
|
||||
gid: task.created_by.gid,
|
||||
resource_type: task.created_by.resource_type,
|
||||
name: task.created_by.name,
|
||||
}
|
||||
: undefined,
|
||||
due_on: task.due_on || undefined,
|
||||
created_at: task.created_at,
|
||||
modified_at: task.modified_at,
|
||||
})),
|
||||
next_page: result.next_page,
|
||||
},
|
||||
ts: new Date().toISOString(),
|
||||
tasks: tasks.map((task: any) => ({
|
||||
gid: task.gid,
|
||||
resource_type: task.resource_type,
|
||||
resource_subtype: task.resource_subtype,
|
||||
name: task.name,
|
||||
notes: task.notes || '',
|
||||
completed: task.completed || false,
|
||||
assignee: task.assignee
|
||||
? {
|
||||
gid: task.assignee.gid,
|
||||
name: task.assignee.name,
|
||||
}
|
||||
: undefined,
|
||||
created_by: task.created_by
|
||||
? {
|
||||
gid: task.created_by.gid,
|
||||
resource_type: task.created_by.resource_type,
|
||||
name: task.created_by.name,
|
||||
}
|
||||
: undefined,
|
||||
due_on: task.due_on || undefined,
|
||||
created_at: task.created_at,
|
||||
modified_at: task.modified_at,
|
||||
})),
|
||||
next_page: result.next_page,
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error processing request:', error)
|
||||
|
||||
@@ -96,34 +96,32 @@ export async function POST(request: Request) {
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
tasks: tasks.map((task: any) => ({
|
||||
gid: task.gid,
|
||||
resource_type: task.resource_type,
|
||||
resource_subtype: task.resource_subtype,
|
||||
name: task.name,
|
||||
notes: task.notes || '',
|
||||
completed: task.completed || false,
|
||||
assignee: task.assignee
|
||||
? {
|
||||
gid: task.assignee.gid,
|
||||
name: task.assignee.name,
|
||||
}
|
||||
: undefined,
|
||||
created_by: task.created_by
|
||||
? {
|
||||
gid: task.created_by.gid,
|
||||
resource_type: task.created_by.resource_type,
|
||||
name: task.created_by.name,
|
||||
}
|
||||
: undefined,
|
||||
due_on: task.due_on || undefined,
|
||||
created_at: task.created_at,
|
||||
modified_at: task.modified_at,
|
||||
})),
|
||||
next_page: result.next_page,
|
||||
},
|
||||
ts: new Date().toISOString(),
|
||||
tasks: tasks.map((task: any) => ({
|
||||
gid: task.gid,
|
||||
resource_type: task.resource_type,
|
||||
resource_subtype: task.resource_subtype,
|
||||
name: task.name,
|
||||
notes: task.notes || '',
|
||||
completed: task.completed || false,
|
||||
assignee: task.assignee
|
||||
? {
|
||||
gid: task.assignee.gid,
|
||||
name: task.assignee.name,
|
||||
}
|
||||
: undefined,
|
||||
created_by: task.created_by
|
||||
? {
|
||||
gid: task.created_by.gid,
|
||||
resource_type: task.created_by.resource_type,
|
||||
name: task.created_by.name,
|
||||
}
|
||||
: undefined,
|
||||
due_on: task.due_on || undefined,
|
||||
created_at: task.created_at,
|
||||
modified_at: task.modified_at,
|
||||
})),
|
||||
next_page: result.next_page,
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error processing request:', error)
|
||||
|
||||
@@ -99,14 +99,12 @@ export async function PUT(request: Request) {
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
gid: task.gid,
|
||||
name: task.name,
|
||||
notes: task.notes || '',
|
||||
completed: task.completed || false,
|
||||
modified_at: task.modified_at,
|
||||
},
|
||||
ts: new Date().toISOString(),
|
||||
gid: task.gid,
|
||||
name: task.name,
|
||||
notes: task.notes || '',
|
||||
completed: task.completed || false,
|
||||
modified_at: task.modified_at,
|
||||
})
|
||||
} catch (error: any) {
|
||||
logger.error('Error updating Asana task:', {
|
||||
|
||||
@@ -31,6 +31,16 @@ export async function POST(request: Request) {
|
||||
return NextResponse.json({ error: 'Space ID is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!/^\d+$/.test(String(spaceId))) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error:
|
||||
'Invalid Space ID. The Space ID must be a numeric value, not the space key from the URL. Use the "list" operation to get all spaces with their numeric IDs.',
|
||||
},
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
if (!title) {
|
||||
return NextResponse.json({ error: 'Title is required' }, { status: 400 })
|
||||
}
|
||||
@@ -91,10 +101,24 @@ export async function POST(request: Request) {
|
||||
statusText: response.statusText,
|
||||
error: JSON.stringify(errorData, null, 2),
|
||||
})
|
||||
const errorMessage =
|
||||
errorData?.message ||
|
||||
(errorData?.errors && JSON.stringify(errorData.errors)) ||
|
||||
`Failed to create Confluence page (${response.status})`
|
||||
|
||||
let errorMessage = `Failed to create Confluence page (${response.status})`
|
||||
if (errorData?.message) {
|
||||
errorMessage = errorData.message
|
||||
} else if (errorData?.errors && Array.isArray(errorData.errors)) {
|
||||
const firstError = errorData.errors[0]
|
||||
if (firstError?.title) {
|
||||
if (firstError.title.includes("'spaceId'") && firstError.title.includes('Long')) {
|
||||
errorMessage =
|
||||
'Invalid Space ID. Use the list spaces operation to find valid space IDs.'
|
||||
} else {
|
||||
errorMessage = firstError.title
|
||||
}
|
||||
} else {
|
||||
errorMessage = JSON.stringify(errorData.errors)
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: errorMessage }, { status: response.status })
|
||||
}
|
||||
|
||||
|
||||
135
apps/sim/app/api/tools/confluence/upload-attachment/route.ts
Normal file
135
apps/sim/app/api/tools/confluence/upload-attachment/route.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
|
||||
import { createLogger } from '@/lib/logs/console/logger'
|
||||
import { processSingleFileToUserFile } from '@/lib/uploads/utils/file-utils'
|
||||
import { downloadFileFromStorage } from '@/lib/uploads/utils/file-utils.server'
|
||||
import { getConfluenceCloudId } from '@/tools/confluence/utils'
|
||||
|
||||
const logger = createLogger('ConfluenceUploadAttachmentAPI')
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { domain, accessToken, cloudId: providedCloudId, pageId, file, fileName, comment } = body
|
||||
|
||||
if (!domain) {
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!pageId) {
|
||||
return NextResponse.json({ error: 'Page ID is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
return NextResponse.json({ error: 'File is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const pageIdValidation = validateAlphanumericId(pageId, 'pageId', 255)
|
||||
if (!pageIdValidation.isValid) {
|
||||
return NextResponse.json({ error: pageIdValidation.error }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = providedCloudId || (await getConfluenceCloudId(domain, accessToken))
|
||||
|
||||
const cloudIdValidation = validateJiraCloudId(cloudId, 'cloudId')
|
||||
if (!cloudIdValidation.isValid) {
|
||||
return NextResponse.json({ error: cloudIdValidation.error }, { status: 400 })
|
||||
}
|
||||
|
||||
let fileToProcess = file
|
||||
if (Array.isArray(file)) {
|
||||
if (file.length === 0) {
|
||||
return NextResponse.json({ error: 'No file provided' }, { status: 400 })
|
||||
}
|
||||
fileToProcess = file[0]
|
||||
}
|
||||
|
||||
let userFile
|
||||
try {
|
||||
userFile = processSingleFileToUserFile(fileToProcess, 'confluence-upload', logger)
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ error: error instanceof Error ? error.message : 'Failed to process file' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
let fileBuffer: Buffer
|
||||
try {
|
||||
fileBuffer = await downloadFileFromStorage(userFile, 'confluence-upload', logger)
|
||||
} catch (error) {
|
||||
logger.error('Failed to download file from storage:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: `Failed to download file: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
|
||||
const uploadFileName = fileName || userFile.name || 'attachment'
|
||||
const mimeType = userFile.type || 'application/octet-stream'
|
||||
|
||||
const url = `https://api.atlassian.com/ex/confluence/${cloudId}/wiki/rest/api/content/${pageId}/child/attachment`
|
||||
|
||||
const formData = new FormData()
|
||||
const blob = new Blob([new Uint8Array(fileBuffer)], { type: mimeType })
|
||||
formData.append('file', blob, uploadFileName)
|
||||
|
||||
if (comment) {
|
||||
formData.append('comment', comment)
|
||||
}
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'X-Atlassian-Token': 'nocheck',
|
||||
},
|
||||
body: formData,
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => null)
|
||||
logger.error('Confluence API error response:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
error: JSON.stringify(errorData, null, 2),
|
||||
})
|
||||
|
||||
let errorMessage = `Failed to upload attachment to Confluence (${response.status})`
|
||||
if (errorData?.message) {
|
||||
errorMessage = errorData.message
|
||||
} else if (errorData?.errorMessage) {
|
||||
errorMessage = errorData.errorMessage
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: errorMessage }, { status: response.status })
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
const attachment = data.results?.[0] || data
|
||||
|
||||
return NextResponse.json({
|
||||
attachmentId: attachment.id,
|
||||
title: attachment.title,
|
||||
fileSize: attachment.extensions?.fileSize || 0,
|
||||
mediaType: attachment.extensions?.mediaType || mimeType,
|
||||
downloadUrl: attachment._links?.download || '',
|
||||
pageId: pageId,
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error uploading Confluence attachment:', error)
|
||||
return NextResponse.json(
|
||||
{ error: (error as Error).message || 'Internal server error' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,10 @@ import { z } from 'zod'
|
||||
import { checkHybridAuth } from '@/lib/auth/hybrid'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { createLogger } from '@/lib/logs/console/logger'
|
||||
import { processSingleFileToUserFile } from '@/lib/uploads/utils/file-utils'
|
||||
import {
|
||||
getExtensionFromMimeType,
|
||||
processSingleFileToUserFile,
|
||||
} from '@/lib/uploads/utils/file-utils'
|
||||
import { downloadFileFromStorage } from '@/lib/uploads/utils/file-utils.server'
|
||||
import { normalizeExcelValues } from '@/tools/onedrive/utils'
|
||||
|
||||
@@ -27,9 +30,8 @@ const OneDriveUploadSchema = z.object({
|
||||
fileName: z.string().min(1, 'File name is required'),
|
||||
file: z.any().optional(), // UserFile object (optional for blank Excel creation)
|
||||
folderId: z.string().optional().nullable(),
|
||||
mimeType: z.string().optional(),
|
||||
// Optional Excel write-after-create inputs
|
||||
values: ExcelValuesSchema.optional(),
|
||||
mimeType: z.string().nullish(), // Accept string, null, or undefined
|
||||
values: ExcelValuesSchema.optional().nullable(),
|
||||
})
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
@@ -149,9 +151,17 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
}
|
||||
|
||||
// Ensure file name has correct extension for Excel files
|
||||
// Ensure file name has an appropriate extension
|
||||
let fileName = validatedData.fileName
|
||||
if (isExcelCreation && !fileName.endsWith('.xlsx')) {
|
||||
const hasExtension = fileName.includes('.') && fileName.lastIndexOf('.') > 0
|
||||
|
||||
if (!hasExtension) {
|
||||
const extension = getExtensionFromMimeType(mimeType)
|
||||
if (extension) {
|
||||
fileName = `${fileName}.${extension}`
|
||||
logger.info(`[${requestId}] Added extension to filename: ${fileName}`)
|
||||
}
|
||||
} else if (isExcelCreation && !fileName.endsWith('.xlsx')) {
|
||||
fileName = `${fileName.replace(/\.[^.]*$/, '')}.xlsx`
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import type React from 'react'
|
||||
import {
|
||||
SUPPORTED_AUDIO_EXTENSIONS,
|
||||
SUPPORTED_VIDEO_EXTENSIONS,
|
||||
} from '@/lib/uploads/utils/validation'
|
||||
|
||||
interface IconProps {
|
||||
className?: string
|
||||
@@ -223,13 +227,19 @@ export const DefaultFileIcon: React.FC<IconProps> = ({ className = 'w-6 h-6' })
|
||||
export function getDocumentIcon(mimeType: string, filename: string): React.FC<IconProps> {
|
||||
const extension = filename.split('.').pop()?.toLowerCase()
|
||||
|
||||
const audioExtensions = ['mp3', 'm4a', 'wav', 'webm', 'ogg', 'flac', 'aac', 'opus']
|
||||
if (mimeType.startsWith('audio/') || (extension && audioExtensions.includes(extension))) {
|
||||
if (
|
||||
mimeType.startsWith('audio/') ||
|
||||
(extension &&
|
||||
SUPPORTED_AUDIO_EXTENSIONS.includes(extension as (typeof SUPPORTED_AUDIO_EXTENSIONS)[number]))
|
||||
) {
|
||||
return AudioIcon
|
||||
}
|
||||
|
||||
const videoExtensions = ['mp4', 'mov', 'avi', 'mkv']
|
||||
if (mimeType.startsWith('video/') || (extension && videoExtensions.includes(extension))) {
|
||||
if (
|
||||
mimeType.startsWith('video/') ||
|
||||
(extension &&
|
||||
SUPPORTED_VIDEO_EXTENSIONS.includes(extension as (typeof SUPPORTED_VIDEO_EXTENSIONS)[number]))
|
||||
) {
|
||||
return VideoIcon
|
||||
}
|
||||
|
||||
|
||||
@@ -207,6 +207,18 @@ const generateOutputPaths = (outputs: Record<string, any>, prefix = ''): string[
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
if ('type' in value && typeof value.type === 'string') {
|
||||
paths.push(currentPath)
|
||||
if (value.type === 'object' && value.properties) {
|
||||
paths.push(...generateOutputPaths(value.properties, currentPath))
|
||||
} else if (value.type === 'array' && value.items?.properties) {
|
||||
paths.push(...generateOutputPaths(value.items.properties, currentPath))
|
||||
} else if (
|
||||
value.type === 'array' &&
|
||||
value.items &&
|
||||
typeof value.items === 'object' &&
|
||||
!('type' in value.items)
|
||||
) {
|
||||
paths.push(...generateOutputPaths(value.items, currentPath))
|
||||
}
|
||||
} else {
|
||||
const subPaths = generateOutputPaths(value, currentPath)
|
||||
paths.push(...subPaths)
|
||||
|
||||
@@ -287,6 +287,19 @@ export const AsanaBlock: BlockConfig<AsanaResponse> = {
|
||||
},
|
||||
outputs: {
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: { type: 'string', description: 'Operation result (JSON)' },
|
||||
ts: { type: 'string', description: 'Timestamp of the response' },
|
||||
gid: { type: 'string', description: 'Resource globally unique identifier' },
|
||||
name: { type: 'string', description: 'Resource name' },
|
||||
notes: { type: 'string', description: 'Task notes or description' },
|
||||
completed: { type: 'boolean', description: 'Whether the task is completed' },
|
||||
text: { type: 'string', description: 'Comment text content' },
|
||||
assignee: { type: 'json', description: 'Assignee details (gid, name)' },
|
||||
created_by: { type: 'json', description: 'Creator details (gid, name)' },
|
||||
due_on: { type: 'string', description: 'Due date (YYYY-MM-DD)' },
|
||||
created_at: { type: 'string', description: 'Creation timestamp' },
|
||||
modified_at: { type: 'string', description: 'Last modified timestamp' },
|
||||
permalink_url: { type: 'string', description: 'URL to the resource in Asana' },
|
||||
tasks: { type: 'json', description: 'Array of tasks' },
|
||||
projects: { type: 'json', description: 'Array of projects' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
|
||||
{ label: 'List Comments', id: 'list_comments' },
|
||||
{ label: 'Update Comment', id: 'update_comment' },
|
||||
{ label: 'Delete Comment', id: 'delete_comment' },
|
||||
{ label: 'Upload Attachment', id: 'upload_attachment' },
|
||||
{ label: 'List Attachments', id: 'list_attachments' },
|
||||
{ label: 'Delete Attachment', id: 'delete_attachment' },
|
||||
{ label: 'List Labels', id: 'list_labels' },
|
||||
@@ -155,6 +156,28 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
|
||||
required: true,
|
||||
condition: { field: 'operation', value: 'delete_attachment' },
|
||||
},
|
||||
{
|
||||
id: 'attachmentFile',
|
||||
title: 'File',
|
||||
type: 'file-upload',
|
||||
placeholder: 'Select file to upload',
|
||||
required: true,
|
||||
condition: { field: 'operation', value: 'upload_attachment' },
|
||||
},
|
||||
{
|
||||
id: 'attachmentFileName',
|
||||
title: 'File Name',
|
||||
type: 'short-input',
|
||||
placeholder: 'Optional custom file name',
|
||||
condition: { field: 'operation', value: 'upload_attachment' },
|
||||
},
|
||||
{
|
||||
id: 'attachmentComment',
|
||||
title: 'Comment',
|
||||
type: 'short-input',
|
||||
placeholder: 'Optional comment for the attachment',
|
||||
condition: { field: 'operation', value: 'upload_attachment' },
|
||||
},
|
||||
{
|
||||
id: 'labelName',
|
||||
title: 'Label Name',
|
||||
@@ -185,6 +208,7 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
|
||||
'confluence_list_comments',
|
||||
'confluence_update_comment',
|
||||
'confluence_delete_comment',
|
||||
'confluence_upload_attachment',
|
||||
'confluence_list_attachments',
|
||||
'confluence_delete_attachment',
|
||||
'confluence_list_labels',
|
||||
@@ -212,6 +236,8 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
|
||||
return 'confluence_update_comment'
|
||||
case 'delete_comment':
|
||||
return 'confluence_delete_comment'
|
||||
case 'upload_attachment':
|
||||
return 'confluence_upload_attachment'
|
||||
case 'list_attachments':
|
||||
return 'confluence_list_attachments'
|
||||
case 'delete_attachment':
|
||||
@@ -227,11 +253,19 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const { credential, pageId, manualPageId, operation, ...rest } = params
|
||||
const {
|
||||
credential,
|
||||
pageId,
|
||||
manualPageId,
|
||||
operation,
|
||||
attachmentFile,
|
||||
attachmentFileName,
|
||||
attachmentComment,
|
||||
...rest
|
||||
} = params
|
||||
|
||||
const effectivePageId = (pageId || manualPageId || '').trim()
|
||||
|
||||
// Operations that require pageId
|
||||
const requiresPageId = [
|
||||
'read',
|
||||
'update',
|
||||
@@ -240,9 +274,9 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
|
||||
'list_comments',
|
||||
'list_attachments',
|
||||
'list_labels',
|
||||
'upload_attachment',
|
||||
]
|
||||
|
||||
// Operations that require spaceId
|
||||
const requiresSpaceId = ['create', 'get_space']
|
||||
|
||||
if (requiresPageId.includes(operation) && !effectivePageId) {
|
||||
@@ -253,6 +287,18 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
|
||||
throw new Error('Space ID is required for this operation.')
|
||||
}
|
||||
|
||||
if (operation === 'upload_attachment') {
|
||||
return {
|
||||
credential,
|
||||
pageId: effectivePageId,
|
||||
operation,
|
||||
file: attachmentFile,
|
||||
fileName: attachmentFileName,
|
||||
comment: attachmentComment,
|
||||
...rest,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
credential,
|
||||
pageId: effectivePageId || undefined,
|
||||
@@ -276,6 +322,9 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
|
||||
comment: { type: 'string', description: 'Comment text' },
|
||||
commentId: { type: 'string', description: 'Comment identifier' },
|
||||
attachmentId: { type: 'string', description: 'Attachment identifier' },
|
||||
attachmentFile: { type: 'json', description: 'File to upload as attachment' },
|
||||
attachmentFileName: { type: 'string', description: 'Custom file name for attachment' },
|
||||
attachmentComment: { type: 'string', description: 'Comment for the attachment' },
|
||||
labelName: { type: 'string', description: 'Label name' },
|
||||
limit: { type: 'number', description: 'Maximum number of results' },
|
||||
},
|
||||
@@ -297,6 +346,9 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
|
||||
spaces: { type: 'array', description: 'List of spaces' },
|
||||
commentId: { type: 'string', description: 'Comment identifier' },
|
||||
attachmentId: { type: 'string', description: 'Attachment identifier' },
|
||||
fileSize: { type: 'number', description: 'Attachment file size in bytes' },
|
||||
mediaType: { type: 'string', description: 'Attachment MIME type' },
|
||||
downloadUrl: { type: 'string', description: 'Attachment download URL' },
|
||||
labelName: { type: 'string', description: 'Label name' },
|
||||
spaceId: { type: 'string', description: 'Space identifier' },
|
||||
name: { type: 'string', description: 'Space name' },
|
||||
|
||||
@@ -312,6 +312,12 @@ export const GoogleGroupsBlock: BlockConfig = {
|
||||
roles: { type: 'string', description: 'Filter by roles for list members' },
|
||||
},
|
||||
outputs: {
|
||||
output: { type: 'json', description: 'Google Groups API response data' },
|
||||
groups: { type: 'json', description: 'Array of group objects (for list_groups)' },
|
||||
group: { type: 'json', description: 'Single group object (for get/create/update_group)' },
|
||||
members: { type: 'json', description: 'Array of member objects (for list_members)' },
|
||||
member: { type: 'json', description: 'Single member object (for get/add/update_member)' },
|
||||
isMember: { type: 'boolean', description: 'Membership check result (for has_member)' },
|
||||
message: { type: 'string', description: 'Success message (for delete/remove operations)' },
|
||||
nextPageToken: { type: 'string', description: 'Token for fetching next page of results' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -257,9 +257,16 @@ export const GoogleVaultBlock: BlockConfig = {
|
||||
description: { type: 'string', description: 'Matter description' },
|
||||
},
|
||||
outputs: {
|
||||
// Common outputs
|
||||
output: { type: 'json', description: 'Vault API response data' },
|
||||
// Download export file output
|
||||
matters: { type: 'json', description: 'Array of matter objects (for list_matters)' },
|
||||
exports: { type: 'json', description: 'Array of export objects (for list_matters_export)' },
|
||||
holds: { type: 'json', description: 'Array of hold objects (for list_matters_holds)' },
|
||||
matter: { type: 'json', description: 'Created matter object (for create_matters)' },
|
||||
export: { type: 'json', description: 'Created export object (for create_matters_export)' },
|
||||
hold: { type: 'json', description: 'Created hold object (for create_matters_holds)' },
|
||||
file: { type: 'json', description: 'Downloaded export file (UserFile) from execution files' },
|
||||
nextPageToken: {
|
||||
type: 'string',
|
||||
description: 'Token for fetching next page of results (for list operations)',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -72,21 +72,37 @@ export const HubSpotBlock: BlockConfig<HubSpotResponse> = {
|
||||
id: 'contactId',
|
||||
title: 'Contact ID or Email',
|
||||
type: 'short-input',
|
||||
placeholder: 'Optional - Leave empty to list all contacts',
|
||||
condition: { field: 'operation', value: ['get_contacts', 'update_contact'] },
|
||||
placeholder: 'Leave empty to list all contacts',
|
||||
condition: { field: 'operation', value: 'get_contacts' },
|
||||
},
|
||||
{
|
||||
id: 'contactId',
|
||||
title: 'Contact ID or Email',
|
||||
type: 'short-input',
|
||||
placeholder: 'Numeric ID, or email (requires ID Property below)',
|
||||
condition: { field: 'operation', value: 'update_contact' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'companyId',
|
||||
title: 'Company ID or Domain',
|
||||
type: 'short-input',
|
||||
placeholder: 'Optional - Leave empty to list all companies',
|
||||
condition: { field: 'operation', value: ['get_companies', 'update_company'] },
|
||||
placeholder: 'Leave empty to list all companies',
|
||||
condition: { field: 'operation', value: 'get_companies' },
|
||||
},
|
||||
{
|
||||
id: 'companyId',
|
||||
title: 'Company ID or Domain',
|
||||
type: 'short-input',
|
||||
placeholder: 'Numeric ID, or domain (requires ID Property below)',
|
||||
condition: { field: 'operation', value: 'update_company' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'idProperty',
|
||||
title: 'ID Property',
|
||||
type: 'short-input',
|
||||
placeholder: 'Optional - e.g., "email" for contacts, "domain" for companies',
|
||||
placeholder: 'Required if using email/domain (e.g., "email" or "domain")',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['get_contacts', 'update_contact', 'get_companies', 'update_company'],
|
||||
@@ -822,33 +838,48 @@ Return ONLY the JSON array of property names - no explanations, no markdown, no
|
||||
credential,
|
||||
}
|
||||
|
||||
if (propertiesToSet) {
|
||||
const createUpdateOps = [
|
||||
'create_contact',
|
||||
'update_contact',
|
||||
'create_company',
|
||||
'update_company',
|
||||
]
|
||||
if (propertiesToSet && createUpdateOps.includes(operation as string)) {
|
||||
cleanParams.properties = propertiesToSet
|
||||
}
|
||||
|
||||
if (properties && !searchProperties) {
|
||||
const getListOps = ['get_contacts', 'get_companies', 'get_deals']
|
||||
if (properties && !searchProperties && getListOps.includes(operation as string)) {
|
||||
cleanParams.properties = properties
|
||||
}
|
||||
|
||||
if (searchProperties) {
|
||||
const searchOps = ['search_contacts', 'search_companies']
|
||||
if (searchProperties && searchOps.includes(operation as string)) {
|
||||
cleanParams.properties = searchProperties
|
||||
}
|
||||
|
||||
if (filterGroups) {
|
||||
if (filterGroups && searchOps.includes(operation as string)) {
|
||||
cleanParams.filterGroups = filterGroups
|
||||
}
|
||||
|
||||
if (sorts) {
|
||||
if (sorts && searchOps.includes(operation as string)) {
|
||||
cleanParams.sorts = sorts
|
||||
}
|
||||
|
||||
if (associations) {
|
||||
if (associations && ['create_contact', 'create_company'].includes(operation as string)) {
|
||||
cleanParams.associations = associations
|
||||
}
|
||||
|
||||
// Add other params
|
||||
const excludeKeys = [
|
||||
'propertiesToSet',
|
||||
'properties',
|
||||
'searchProperties',
|
||||
'filterGroups',
|
||||
'sorts',
|
||||
'associations',
|
||||
]
|
||||
Object.entries(rest).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
if (value !== undefined && value !== null && value !== '' && !excludeKeys.includes(key)) {
|
||||
cleanParams[key] = value
|
||||
}
|
||||
})
|
||||
|
||||
@@ -214,6 +214,75 @@ export function getMimeTypeFromExtension(extension: string): string {
|
||||
return extensionMimeMap[extension.toLowerCase()] || 'application/octet-stream'
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file extension from MIME type
|
||||
* @param mimeType - MIME type string
|
||||
* @returns File extension without dot, or null if not found
|
||||
*/
|
||||
export function getExtensionFromMimeType(mimeType: string): string | null {
|
||||
const mimeToExtension: Record<string, string> = {
|
||||
// Images
|
||||
'image/jpeg': 'jpg',
|
||||
'image/jpg': 'jpg',
|
||||
'image/png': 'png',
|
||||
'image/gif': 'gif',
|
||||
'image/webp': 'webp',
|
||||
'image/svg+xml': 'svg',
|
||||
|
||||
// Documents
|
||||
'application/pdf': 'pdf',
|
||||
'text/plain': 'txt',
|
||||
'text/csv': 'csv',
|
||||
'application/json': 'json',
|
||||
'application/xml': 'xml',
|
||||
'text/xml': 'xml',
|
||||
'text/html': 'html',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
|
||||
'application/msword': 'doc',
|
||||
'application/vnd.ms-excel': 'xls',
|
||||
'application/vnd.ms-powerpoint': 'ppt',
|
||||
'text/markdown': 'md',
|
||||
'application/rtf': 'rtf',
|
||||
|
||||
// Audio
|
||||
'audio/mpeg': 'mp3',
|
||||
'audio/mp3': 'mp3',
|
||||
'audio/mp4': 'm4a',
|
||||
'audio/x-m4a': 'm4a',
|
||||
'audio/m4a': 'm4a',
|
||||
'audio/wav': 'wav',
|
||||
'audio/wave': 'wav',
|
||||
'audio/x-wav': 'wav',
|
||||
'audio/webm': 'webm',
|
||||
'audio/ogg': 'ogg',
|
||||
'audio/vorbis': 'ogg',
|
||||
'audio/flac': 'flac',
|
||||
'audio/x-flac': 'flac',
|
||||
'audio/aac': 'aac',
|
||||
'audio/x-aac': 'aac',
|
||||
'audio/opus': 'opus',
|
||||
|
||||
// Video
|
||||
'video/mp4': 'mp4',
|
||||
'video/mpeg': 'mpg',
|
||||
'video/quicktime': 'mov',
|
||||
'video/x-quicktime': 'mov',
|
||||
'video/x-msvideo': 'avi',
|
||||
'video/avi': 'avi',
|
||||
'video/x-matroska': 'mkv',
|
||||
'video/webm': 'webm',
|
||||
|
||||
// Archives
|
||||
'application/zip': 'zip',
|
||||
'application/x-zip-compressed': 'zip',
|
||||
'application/gzip': 'gz',
|
||||
}
|
||||
|
||||
return mimeToExtension[mimeType.toLowerCase()] || null
|
||||
}
|
||||
|
||||
/**
|
||||
* Format bytes to human-readable file size
|
||||
* @param bytes - File size in bytes
|
||||
|
||||
@@ -101,7 +101,6 @@ export const apifyRunActorSyncTool: ToolConfig<RunActorParams, RunActorResult> =
|
||||
success: { type: 'boolean', description: 'Whether the actor run succeeded' },
|
||||
runId: { type: 'string', description: 'APIFY run ID' },
|
||||
status: { type: 'string', description: 'Run status (SUCCEEDED, FAILED, etc.)' },
|
||||
datasetId: { type: 'string', description: 'Dataset ID containing results' },
|
||||
items: { type: 'array', description: 'Dataset items (if completed)' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -52,31 +52,33 @@ export const asanaAddCommentTool: ToolConfig<AsanaAddCommentParams, AsanaAddComm
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {},
|
||||
error: 'Empty response from Asana',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
const { success, error, ...output } = data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || null,
|
||||
error: data.error,
|
||||
success: success ?? true,
|
||||
output,
|
||||
error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
success: {
|
||||
type: 'boolean',
|
||||
description: 'Operation success status',
|
||||
},
|
||||
output: {
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
ts: { type: 'string', description: 'Timestamp of the response' },
|
||||
gid: { type: 'string', description: 'Comment globally unique identifier' },
|
||||
text: { type: 'string', description: 'Comment text content' },
|
||||
created_at: { type: 'string', description: 'Comment creation timestamp' },
|
||||
created_by: {
|
||||
type: 'object',
|
||||
description: 'Comment details including gid, text, created timestamp, and author',
|
||||
description: 'Comment author details',
|
||||
properties: {
|
||||
gid: { type: 'string', description: 'Author GID' },
|
||||
name: { type: 'string', description: 'Author name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -86,34 +86,22 @@ export const asanaCreateTaskTool: ToolConfig<AsanaCreateTaskParams, AsanaCreateT
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
const { success, error, ...output } = data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
gid: 'unknown',
|
||||
name: 'Task creation failed',
|
||||
notes: '',
|
||||
completed: false,
|
||||
created_at: new Date().toISOString(),
|
||||
permalink_url: '',
|
||||
},
|
||||
error: data.error,
|
||||
success: success ?? true,
|
||||
output,
|
||||
error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
success: {
|
||||
type: 'boolean',
|
||||
description: 'Operation success status',
|
||||
},
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Created task details with timestamp, gid, name, notes, and permalink',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
ts: { type: 'string', description: 'Timestamp of the response' },
|
||||
gid: { type: 'string', description: 'Task globally unique identifier' },
|
||||
name: { type: 'string', description: 'Task name' },
|
||||
notes: { type: 'string', description: 'Task notes or description' },
|
||||
completed: { type: 'boolean', description: 'Whether the task is completed' },
|
||||
created_at: { type: 'string', description: 'Task creation timestamp' },
|
||||
permalink_url: { type: 'string', description: 'URL to the task in Asana' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -45,31 +45,34 @@ export const asanaGetProjectsTool: ToolConfig<AsanaGetProjectsParams, AsanaGetPr
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {},
|
||||
error: 'Empty response from Asana',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
const { success, error, ...output } = data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || { ts: new Date().toISOString(), projects: [] },
|
||||
error: data.error,
|
||||
success: success ?? true,
|
||||
output,
|
||||
error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
success: {
|
||||
type: 'boolean',
|
||||
description: 'Operation success status',
|
||||
},
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'List of projects with their gid, name, and resource type',
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
ts: { type: 'string', description: 'Timestamp of the response' },
|
||||
projects: {
|
||||
type: 'array',
|
||||
description: 'Array of projects',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
gid: { type: 'string', description: 'Project GID' },
|
||||
name: { type: 'string', description: 'Project name' },
|
||||
resource_type: { type: 'string', description: 'Resource type (project)' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -67,32 +67,59 @@ export const asanaGetTaskTool: ToolConfig<AsanaGetTaskParams, AsanaGetTaskRespon
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {},
|
||||
error: 'Empty response from Asana',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
const { success, error, ...output } = data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || null,
|
||||
error: data.error,
|
||||
success: success ?? true,
|
||||
output,
|
||||
error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
success: {
|
||||
type: 'boolean',
|
||||
description: 'Operation success status',
|
||||
},
|
||||
output: {
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
ts: { type: 'string', description: 'Timestamp of the response' },
|
||||
gid: { type: 'string', description: 'Task globally unique identifier' },
|
||||
resource_type: { type: 'string', description: 'Resource type (task)' },
|
||||
resource_subtype: { type: 'string', description: 'Resource subtype' },
|
||||
name: { type: 'string', description: 'Task name' },
|
||||
notes: { type: 'string', description: 'Task notes or description' },
|
||||
completed: { type: 'boolean', description: 'Whether the task is completed' },
|
||||
assignee: {
|
||||
type: 'object',
|
||||
description:
|
||||
'Single task details or array of tasks, depending on whether taskGid was provided',
|
||||
description: 'Assignee details',
|
||||
properties: {
|
||||
gid: { type: 'string', description: 'Assignee GID' },
|
||||
name: { type: 'string', description: 'Assignee name' },
|
||||
},
|
||||
},
|
||||
created_by: {
|
||||
type: 'object',
|
||||
description: 'Creator details',
|
||||
properties: {
|
||||
gid: { type: 'string', description: 'Creator GID' },
|
||||
name: { type: 'string', description: 'Creator name' },
|
||||
},
|
||||
},
|
||||
due_on: { type: 'string', description: 'Due date (YYYY-MM-DD)' },
|
||||
created_at: { type: 'string', description: 'Task creation timestamp' },
|
||||
modified_at: { type: 'string', description: 'Task last modified timestamp' },
|
||||
tasks: {
|
||||
type: 'array',
|
||||
description: 'Array of tasks (when fetching multiple)',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
gid: { type: 'string', description: 'Task GID' },
|
||||
name: { type: 'string', description: 'Task name' },
|
||||
completed: { type: 'boolean', description: 'Completion status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -73,31 +73,57 @@ export const asanaSearchTasksTool: ToolConfig<AsanaSearchTasksParams, AsanaSearc
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {},
|
||||
error: 'Empty response from Asana',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
const { success, error, ...output } = data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || { ts: new Date().toISOString(), tasks: [] },
|
||||
error: data.error,
|
||||
success: success ?? true,
|
||||
output,
|
||||
error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
success: {
|
||||
type: 'boolean',
|
||||
description: 'Operation success status',
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
ts: { type: 'string', description: 'Timestamp of the response' },
|
||||
tasks: {
|
||||
type: 'array',
|
||||
description: 'Array of matching tasks',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
gid: { type: 'string', description: 'Task GID' },
|
||||
resource_type: { type: 'string', description: 'Resource type' },
|
||||
resource_subtype: { type: 'string', description: 'Resource subtype' },
|
||||
name: { type: 'string', description: 'Task name' },
|
||||
notes: { type: 'string', description: 'Task notes' },
|
||||
completed: { type: 'boolean', description: 'Completion status' },
|
||||
assignee: {
|
||||
type: 'object',
|
||||
description: 'Assignee details',
|
||||
properties: {
|
||||
gid: { type: 'string', description: 'Assignee GID' },
|
||||
name: { type: 'string', description: 'Assignee name' },
|
||||
},
|
||||
},
|
||||
due_on: { type: 'string', description: 'Due date' },
|
||||
created_at: { type: 'string', description: 'Creation timestamp' },
|
||||
modified_at: { type: 'string', description: 'Modified timestamp' },
|
||||
},
|
||||
},
|
||||
},
|
||||
output: {
|
||||
next_page: {
|
||||
type: 'object',
|
||||
description: 'List of tasks matching the search criteria',
|
||||
description: 'Pagination info',
|
||||
properties: {
|
||||
offset: { type: 'string', description: 'Offset token' },
|
||||
path: { type: 'string', description: 'API path' },
|
||||
uri: { type: 'string', description: 'Full URI' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -9,56 +9,52 @@ export interface AsanaGetTaskParams {
|
||||
}
|
||||
|
||||
export interface AsanaGetTaskResponse extends ToolResponse {
|
||||
output:
|
||||
| {
|
||||
ts: string
|
||||
output: {
|
||||
ts: string
|
||||
gid?: string
|
||||
resource_type?: string
|
||||
resource_subtype?: string
|
||||
name?: string
|
||||
notes?: string
|
||||
completed?: boolean
|
||||
assignee?: {
|
||||
gid: string
|
||||
name: string
|
||||
}
|
||||
created_by?: {
|
||||
gid: string
|
||||
resource_type: string
|
||||
name: string
|
||||
}
|
||||
due_on?: string
|
||||
created_at?: string
|
||||
modified_at?: string
|
||||
tasks?: Array<{
|
||||
gid: string
|
||||
resource_type: string
|
||||
resource_subtype: string
|
||||
name: string
|
||||
notes?: string
|
||||
completed: boolean
|
||||
assignee?: {
|
||||
gid: string
|
||||
name: string
|
||||
}
|
||||
created_by?: {
|
||||
gid: string
|
||||
resource_type: string
|
||||
resource_subtype: string
|
||||
name: string
|
||||
notes: string
|
||||
completed: boolean
|
||||
assignee?: {
|
||||
gid: string
|
||||
name: string
|
||||
}
|
||||
created_by?: {
|
||||
gid: string
|
||||
resource_type: string
|
||||
name: string
|
||||
}
|
||||
due_on?: string
|
||||
created_at: string
|
||||
modified_at: string
|
||||
}
|
||||
| {
|
||||
ts: string
|
||||
tasks: Array<{
|
||||
gid: string
|
||||
resource_type: string
|
||||
resource_subtype: string
|
||||
name: string
|
||||
notes?: string
|
||||
completed: boolean
|
||||
assignee?: {
|
||||
gid: string
|
||||
name: string
|
||||
}
|
||||
created_by?: {
|
||||
gid: string
|
||||
resource_type: string
|
||||
name: string
|
||||
}
|
||||
due_on?: string
|
||||
created_at: string
|
||||
modified_at: string
|
||||
}>
|
||||
next_page?: {
|
||||
offset: string
|
||||
path: string
|
||||
uri: string
|
||||
}
|
||||
}
|
||||
due_on?: string
|
||||
created_at: string
|
||||
modified_at: string
|
||||
}>
|
||||
next_page?: {
|
||||
offset: string
|
||||
path: string
|
||||
uri: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface AsanaCreateTaskParams {
|
||||
|
||||
@@ -92,33 +92,21 @@ export const asanaUpdateTaskTool: ToolConfig<AsanaUpdateTaskParams, AsanaUpdateT
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
const { success, error, ...output } = data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
gid: 'unknown',
|
||||
name: 'Task update failed',
|
||||
notes: '',
|
||||
completed: false,
|
||||
modified_at: new Date().toISOString(),
|
||||
},
|
||||
error: data.error,
|
||||
success: success ?? true,
|
||||
output,
|
||||
error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
success: {
|
||||
type: 'boolean',
|
||||
description: 'Operation success status',
|
||||
},
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Updated task details with timestamp, gid, name, notes, and modified timestamp',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
ts: { type: 'string', description: 'Timestamp of the response' },
|
||||
gid: { type: 'string', description: 'Task globally unique identifier' },
|
||||
name: { type: 'string', description: 'Task name' },
|
||||
notes: { type: 'string', description: 'Task notes or description' },
|
||||
completed: { type: 'boolean', description: 'Whether the task is completed' },
|
||||
modified_at: { type: 'string', description: 'Task last modified timestamp' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { confluenceRetrieveTool } from '@/tools/confluence/retrieve'
|
||||
import { confluenceSearchTool } from '@/tools/confluence/search'
|
||||
import { confluenceUpdateTool } from '@/tools/confluence/update'
|
||||
import { confluenceUpdateCommentTool } from '@/tools/confluence/update_comment'
|
||||
import { confluenceUploadAttachmentTool } from '@/tools/confluence/upload_attachment'
|
||||
|
||||
export {
|
||||
confluenceRetrieveTool,
|
||||
@@ -25,6 +26,7 @@ export {
|
||||
confluenceDeleteCommentTool,
|
||||
confluenceListAttachmentsTool,
|
||||
confluenceDeleteAttachmentTool,
|
||||
confluenceUploadAttachmentTool,
|
||||
confluenceListLabelsTool,
|
||||
confluenceGetSpaceTool,
|
||||
confluenceListSpacesTool,
|
||||
|
||||
@@ -142,6 +142,28 @@ export interface ConfluenceAttachmentResponse extends ToolResponse {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ConfluenceUploadAttachmentParams {
|
||||
accessToken: string
|
||||
domain: string
|
||||
pageId: string
|
||||
file: any
|
||||
fileName?: string
|
||||
comment?: string
|
||||
cloudId?: string
|
||||
}
|
||||
|
||||
export interface ConfluenceUploadAttachmentResponse extends ToolResponse {
|
||||
output: {
|
||||
ts: string
|
||||
attachmentId: string
|
||||
title: string
|
||||
fileSize: number
|
||||
mediaType: string
|
||||
downloadUrl: string
|
||||
pageId: string
|
||||
}
|
||||
}
|
||||
|
||||
// Label operations
|
||||
export interface ConfluenceLabelParams {
|
||||
accessToken: string
|
||||
@@ -201,5 +223,6 @@ export type ConfluenceResponse =
|
||||
| ConfluenceSearchResponse
|
||||
| ConfluenceCommentResponse
|
||||
| ConfluenceAttachmentResponse
|
||||
| ConfluenceUploadAttachmentResponse
|
||||
| ConfluenceLabelResponse
|
||||
| ConfluenceSpaceResponse
|
||||
|
||||
134
apps/sim/tools/confluence/upload_attachment.ts
Normal file
134
apps/sim/tools/confluence/upload_attachment.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface ConfluenceUploadAttachmentParams {
|
||||
accessToken: string
|
||||
domain: string
|
||||
pageId: string
|
||||
file: any
|
||||
fileName?: string
|
||||
comment?: string
|
||||
cloudId?: string
|
||||
}
|
||||
|
||||
export interface ConfluenceUploadAttachmentResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
ts: string
|
||||
attachmentId: string
|
||||
title: string
|
||||
fileSize: number
|
||||
mediaType: string
|
||||
downloadUrl: string
|
||||
pageId: string
|
||||
}
|
||||
}
|
||||
|
||||
export const confluenceUploadAttachmentTool: ToolConfig<
|
||||
ConfluenceUploadAttachmentParams,
|
||||
ConfluenceUploadAttachmentResponse
|
||||
> = {
|
||||
id: 'confluence_upload_attachment',
|
||||
name: 'Confluence Upload Attachment',
|
||||
description: 'Upload a file as an attachment to a Confluence page.',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'confluence',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Confluence',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Your Confluence domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
pageId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Confluence page ID to attach the file to',
|
||||
},
|
||||
file: {
|
||||
type: 'file',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The file to upload as an attachment',
|
||||
},
|
||||
fileName: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Optional custom file name for the attachment',
|
||||
},
|
||||
comment: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Optional comment to add to the attachment',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description:
|
||||
'Confluence Cloud ID for the instance. If not provided, it will be fetched using the domain.',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: () => '/api/tools/confluence/upload-attachment',
|
||||
method: 'POST',
|
||||
headers: (params: ConfluenceUploadAttachmentParams) => {
|
||||
return {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
}
|
||||
},
|
||||
body: (params: ConfluenceUploadAttachmentParams) => {
|
||||
return {
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
pageId: params.pageId,
|
||||
file: params.file,
|
||||
fileName: params.fileName,
|
||||
comment: params.comment,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
attachmentId: data.attachmentId || '',
|
||||
title: data.title || '',
|
||||
fileSize: data.fileSize || 0,
|
||||
mediaType: data.mediaType || '',
|
||||
downloadUrl: data.downloadUrl || '',
|
||||
pageId: data.pageId || '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of upload' },
|
||||
attachmentId: { type: 'string', description: 'Uploaded attachment ID' },
|
||||
title: { type: 'string', description: 'Attachment file name' },
|
||||
fileSize: { type: 'number', description: 'File size in bytes' },
|
||||
mediaType: { type: 'string', description: 'MIME type of the attachment' },
|
||||
downloadUrl: { type: 'string', description: 'Download URL for the attachment' },
|
||||
pageId: { type: 'string', description: 'Page ID the attachment was added to' },
|
||||
},
|
||||
}
|
||||
@@ -66,7 +66,11 @@ export const addMemberTool: ToolConfig<GoogleGroupsAddMemberParams, GoogleGroups
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: data,
|
||||
output: { member: data },
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
member: { type: 'json', description: 'Added member object' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -67,7 +67,11 @@ export const createGroupTool: ToolConfig<GoogleGroupsCreateParams, GoogleGroupsR
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: data,
|
||||
output: { group: data },
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
group: { type: 'json', description: 'Created group object' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -49,4 +49,8 @@ export const deleteGroupTool: ToolConfig<GoogleGroupsDeleteParams, GoogleGroupsR
|
||||
output: { message: 'Group deleted successfully' },
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
message: { type: 'string', description: 'Success message' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -46,7 +46,11 @@ export const getGroupTool: ToolConfig<GoogleGroupsGetParams, GoogleGroupsRespons
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: data,
|
||||
output: { group: data },
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
group: { type: 'json', description: 'Group object' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -53,7 +53,11 @@ export const getMemberTool: ToolConfig<GoogleGroupsGetMemberParams, GoogleGroups
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: data,
|
||||
output: { member: data },
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
member: { type: 'json', description: 'Member object' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -53,7 +53,11 @@ export const hasMemberTool: ToolConfig<GoogleGroupsHasMemberParams, GoogleGroups
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: data,
|
||||
output: { isMember: data.isMember },
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
isMember: { type: 'boolean', description: 'Whether the user is a member of the group' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -91,7 +91,15 @@ export const listGroupsTool: ToolConfig<GoogleGroupsListParams, GoogleGroupsResp
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: data,
|
||||
output: {
|
||||
groups: data.groups || [],
|
||||
nextPageToken: data.nextPageToken,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
groups: { type: 'json', description: 'Array of group objects' },
|
||||
nextPageToken: { type: 'string', description: 'Token for fetching next page of results' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -78,7 +78,15 @@ export const listMembersTool: ToolConfig<GoogleGroupsListMembersParams, GoogleGr
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: data,
|
||||
output: {
|
||||
members: data.members || [],
|
||||
nextPageToken: data.nextPageToken,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
members: { type: 'json', description: 'Array of member objects' },
|
||||
nextPageToken: { type: 'string', description: 'Token for fetching next page of results' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -56,4 +56,8 @@ export const removeMemberTool: ToolConfig<GoogleGroupsRemoveMemberParams, Google
|
||||
output: { message: 'Member removed successfully' },
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
message: { type: 'string', description: 'Success message' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -79,7 +79,11 @@ export const updateGroupTool: ToolConfig<GoogleGroupsUpdateParams, GoogleGroupsR
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: data,
|
||||
output: { group: data },
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
group: { type: 'json', description: 'Updated group object' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -64,7 +64,11 @@ export const updateMemberTool: ToolConfig<GoogleGroupsUpdateMemberParams, Google
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: data,
|
||||
output: { member: data },
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
member: { type: 'json', description: 'Updated member object' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -40,6 +40,10 @@ export const createMattersTool: ToolConfig<GoogleVaultCreateMattersParams> = {
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to create matter')
|
||||
}
|
||||
return { success: true, output: data }
|
||||
return { success: true, output: { matter: data } }
|
||||
},
|
||||
|
||||
outputs: {
|
||||
matter: { type: 'json', description: 'Created matter object' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -91,6 +91,10 @@ export const createMattersExportTool: ToolConfig<GoogleVaultCreateMattersExportP
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to create export')
|
||||
}
|
||||
return { success: true, output: data }
|
||||
return { success: true, output: { export: data } }
|
||||
},
|
||||
|
||||
outputs: {
|
||||
export: { type: 'json', description: 'Created export object' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -81,6 +81,10 @@ export const createMattersHoldsTool: ToolConfig<GoogleVaultCreateMattersHoldsPar
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to create hold')
|
||||
}
|
||||
return { success: true, output: data }
|
||||
return { success: true, output: { hold: data } }
|
||||
},
|
||||
|
||||
outputs: {
|
||||
hold: { type: 'json', description: 'Created hold object' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ export const listMattersTool: ToolConfig<GoogleVaultListMattersParams> = {
|
||||
return `https://vault.googleapis.com/v1/matters/${params.matterId}`
|
||||
}
|
||||
const url = new URL('https://vault.googleapis.com/v1/matters')
|
||||
// Handle pageSize - convert to number if needed
|
||||
if (params.pageSize !== undefined && params.pageSize !== null) {
|
||||
const pageSize = Number(params.pageSize)
|
||||
if (Number.isFinite(pageSize) && pageSize > 0) {
|
||||
@@ -39,18 +38,26 @@ export const listMattersTool: ToolConfig<GoogleVaultListMattersParams> = {
|
||||
}
|
||||
}
|
||||
if (params.pageToken) url.searchParams.set('pageToken', params.pageToken)
|
||||
// Default BASIC view implicitly by omitting 'view' and 'state' params
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({ Authorization: `Bearer ${params.accessToken}` }),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
transformResponse: async (response: Response, params?: GoogleVaultListMattersParams) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to list matters')
|
||||
}
|
||||
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' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import type { GoogleVaultListMattersExportParams } from '@/tools/google_vault/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
// matters.exports.list
|
||||
// GET https://vault.googleapis.com/v1/matters/{matterId}/exports
|
||||
export const listMattersExportTool: ToolConfig<GoogleVaultListMattersExportParams> = {
|
||||
id: 'list_matters_export',
|
||||
name: 'Vault List Exports (by Matter)',
|
||||
@@ -28,7 +26,6 @@ export const listMattersExportTool: ToolConfig<GoogleVaultListMattersExportParam
|
||||
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`)
|
||||
// Handle pageSize - convert to number if needed
|
||||
if (params.pageSize !== undefined && params.pageSize !== null) {
|
||||
const pageSize = Number(params.pageSize)
|
||||
if (Number.isFinite(pageSize) && pageSize > 0) {
|
||||
@@ -42,13 +39,20 @@ export const listMattersExportTool: ToolConfig<GoogleVaultListMattersExportParam
|
||||
headers: (params) => ({ Authorization: `Bearer ${params.accessToken}` }),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
transformResponse: async (response: Response, params?: GoogleVaultListMattersExportParams) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to list exports')
|
||||
}
|
||||
|
||||
// Return the raw API response without modifications
|
||||
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' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ export const listMattersHoldsTool: ToolConfig<GoogleVaultListMattersHoldsParams>
|
||||
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`)
|
||||
// Handle pageSize - convert to number if needed
|
||||
if (params.pageSize !== undefined && params.pageSize !== null) {
|
||||
const pageSize = Number(params.pageSize)
|
||||
if (Number.isFinite(pageSize) && pageSize > 0) {
|
||||
@@ -34,18 +33,26 @@ export const listMattersHoldsTool: ToolConfig<GoogleVaultListMattersHoldsParams>
|
||||
}
|
||||
}
|
||||
if (params.pageToken) url.searchParams.set('pageToken', params.pageToken)
|
||||
// Default BASIC_HOLD implicitly by omitting 'view'
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({ Authorization: `Bearer ${params.accessToken}` }),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
transformResponse: async (response: Response, params?: GoogleVaultListMattersHoldsParams) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to list holds')
|
||||
}
|
||||
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' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -56,8 +56,17 @@ export const hubspotCreateCompanyTool: ToolConfig<
|
||||
}
|
||||
},
|
||||
body: (params) => {
|
||||
let properties = params.properties
|
||||
if (typeof properties === 'string') {
|
||||
try {
|
||||
properties = JSON.parse(properties)
|
||||
} catch (e) {
|
||||
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
|
||||
}
|
||||
}
|
||||
|
||||
const body: any = {
|
||||
properties: params.properties,
|
||||
properties,
|
||||
}
|
||||
|
||||
if (params.associations && params.associations.length > 0) {
|
||||
@@ -90,21 +99,8 @@ export const hubspotCreateCompanyTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
company: { type: 'object', description: 'Created HubSpot company object' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Created company data',
|
||||
properties: {
|
||||
company: {
|
||||
type: 'object',
|
||||
description: 'Created company object with properties and ID',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -59,8 +59,17 @@ export const hubspotCreateContactTool: ToolConfig<
|
||||
}
|
||||
},
|
||||
body: (params) => {
|
||||
let properties = params.properties
|
||||
if (typeof properties === 'string') {
|
||||
try {
|
||||
properties = JSON.parse(properties)
|
||||
} catch (e) {
|
||||
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
|
||||
}
|
||||
}
|
||||
|
||||
const body: any = {
|
||||
properties: params.properties,
|
||||
properties,
|
||||
}
|
||||
|
||||
if (params.associations && params.associations.length > 0) {
|
||||
@@ -93,21 +102,8 @@ export const hubspotCreateContactTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
contact: { type: 'object', description: 'Created HubSpot contact object' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Created contact data',
|
||||
properties: {
|
||||
contact: {
|
||||
type: 'object',
|
||||
description: 'Created contact object with properties and ID',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -103,21 +103,8 @@ export const hubspotGetCompanyTool: ToolConfig<HubSpotGetCompanyParams, HubSpotG
|
||||
},
|
||||
|
||||
outputs: {
|
||||
company: { type: 'object', description: 'HubSpot company object with properties' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Company data',
|
||||
properties: {
|
||||
company: {
|
||||
type: 'object',
|
||||
description: 'Company object with properties',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -103,21 +103,8 @@ export const hubspotGetContactTool: ToolConfig<HubSpotGetContactParams, HubSpotG
|
||||
},
|
||||
|
||||
outputs: {
|
||||
contact: { type: 'object', description: 'HubSpot contact object with properties' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Contact data',
|
||||
properties: {
|
||||
contact: {
|
||||
type: 'object',
|
||||
description: 'Contact object with properties',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -79,21 +79,8 @@ export const hubspotGetUsersTool: ToolConfig<HubSpotGetUsersParams, HubSpotGetUs
|
||||
},
|
||||
|
||||
outputs: {
|
||||
users: { type: 'array', description: 'Array of HubSpot user objects' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Users data',
|
||||
properties: {
|
||||
users: {
|
||||
type: 'array',
|
||||
description: 'Array of user objects',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -112,25 +112,9 @@ export const hubspotListCompaniesTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
companies: { type: 'array', description: 'Array of HubSpot company objects' },
|
||||
paging: { type: 'object', description: 'Pagination information' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Companies data',
|
||||
properties: {
|
||||
companies: {
|
||||
type: 'array',
|
||||
description: 'Array of company objects',
|
||||
},
|
||||
paging: {
|
||||
type: 'object',
|
||||
description: 'Pagination information',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -110,25 +110,9 @@ export const hubspotListContactsTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
contacts: { type: 'array', description: 'Array of HubSpot contact objects' },
|
||||
paging: { type: 'object', description: 'Pagination information' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Contacts data',
|
||||
properties: {
|
||||
contacts: {
|
||||
type: 'array',
|
||||
description: 'Array of contact objects',
|
||||
},
|
||||
paging: {
|
||||
type: 'object',
|
||||
description: 'Pagination information',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -106,25 +106,9 @@ export const hubspotListDealsTool: ToolConfig<HubSpotListDealsParams, HubSpotLis
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deals: { type: 'array', description: 'Array of HubSpot deal objects' },
|
||||
paging: { type: 'object', description: 'Pagination information' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Deals data',
|
||||
properties: {
|
||||
deals: {
|
||||
type: 'array',
|
||||
description: 'Array of deal objects',
|
||||
},
|
||||
paging: {
|
||||
type: 'object',
|
||||
description: 'Pagination information',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -84,17 +84,47 @@ export const hubspotSearchCompaniesTool: ToolConfig<
|
||||
body: (params) => {
|
||||
const body: any = {}
|
||||
|
||||
if (params.filterGroups && params.filterGroups.length > 0) {
|
||||
body.filterGroups = params.filterGroups
|
||||
if (params.filterGroups) {
|
||||
let parsedFilterGroups = params.filterGroups
|
||||
if (typeof params.filterGroups === 'string') {
|
||||
try {
|
||||
parsedFilterGroups = JSON.parse(params.filterGroups)
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid JSON for filterGroups: ${(e as Error).message}`)
|
||||
}
|
||||
}
|
||||
if (Array.isArray(parsedFilterGroups) && parsedFilterGroups.length > 0) {
|
||||
body.filterGroups = parsedFilterGroups
|
||||
}
|
||||
}
|
||||
if (params.sorts && params.sorts.length > 0) {
|
||||
body.sorts = params.sorts
|
||||
if (params.sorts) {
|
||||
let parsedSorts = params.sorts
|
||||
if (typeof params.sorts === 'string') {
|
||||
try {
|
||||
parsedSorts = JSON.parse(params.sorts)
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid JSON for sorts: ${(e as Error).message}`)
|
||||
}
|
||||
}
|
||||
if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {
|
||||
body.sorts = parsedSorts
|
||||
}
|
||||
}
|
||||
if (params.query) {
|
||||
body.query = params.query
|
||||
}
|
||||
if (params.properties && params.properties.length > 0) {
|
||||
body.properties = params.properties
|
||||
if (params.properties) {
|
||||
let parsedProperties = params.properties
|
||||
if (typeof params.properties === 'string') {
|
||||
try {
|
||||
parsedProperties = JSON.parse(params.properties)
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid JSON for properties: ${(e as Error).message}`)
|
||||
}
|
||||
}
|
||||
if (Array.isArray(parsedProperties) && parsedProperties.length > 0) {
|
||||
body.properties = parsedProperties
|
||||
}
|
||||
}
|
||||
if (params.limit) {
|
||||
body.limit = params.limit
|
||||
@@ -115,46 +145,29 @@ export const hubspotSearchCompaniesTool: ToolConfig<
|
||||
throw new Error(data.message || 'Failed to search companies in HubSpot')
|
||||
}
|
||||
|
||||
const result = {
|
||||
companies: data.results || [],
|
||||
total: data.total,
|
||||
paging: data.paging,
|
||||
metadata: {
|
||||
operation: 'search_companies' as const,
|
||||
totalReturned: data.results?.length || 0,
|
||||
total: data.total,
|
||||
},
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
companies: data.results || [],
|
||||
total: data.total,
|
||||
paging: data.paging,
|
||||
metadata: {
|
||||
operation: 'search_companies' as const,
|
||||
totalReturned: data.results?.length || 0,
|
||||
total: data.total,
|
||||
},
|
||||
success: true,
|
||||
},
|
||||
output: result,
|
||||
...result,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
companies: { type: 'array', description: 'Array of matching HubSpot company objects' },
|
||||
total: { type: 'number', description: 'Total number of matching companies' },
|
||||
paging: { type: 'object', description: 'Pagination information' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Search results',
|
||||
properties: {
|
||||
companies: {
|
||||
type: 'array',
|
||||
description: 'Array of matching company objects',
|
||||
},
|
||||
total: {
|
||||
type: 'number',
|
||||
description: 'Total number of matching companies',
|
||||
},
|
||||
paging: {
|
||||
type: 'object',
|
||||
description: 'Pagination information',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -84,17 +84,47 @@ export const hubspotSearchContactsTool: ToolConfig<
|
||||
body: (params) => {
|
||||
const body: any = {}
|
||||
|
||||
if (params.filterGroups && params.filterGroups.length > 0) {
|
||||
body.filterGroups = params.filterGroups
|
||||
if (params.filterGroups) {
|
||||
let parsedFilterGroups = params.filterGroups
|
||||
if (typeof params.filterGroups === 'string') {
|
||||
try {
|
||||
parsedFilterGroups = JSON.parse(params.filterGroups)
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid JSON for filterGroups: ${(e as Error).message}`)
|
||||
}
|
||||
}
|
||||
if (Array.isArray(parsedFilterGroups) && parsedFilterGroups.length > 0) {
|
||||
body.filterGroups = parsedFilterGroups
|
||||
}
|
||||
}
|
||||
if (params.sorts && params.sorts.length > 0) {
|
||||
body.sorts = params.sorts
|
||||
if (params.sorts) {
|
||||
let parsedSorts = params.sorts
|
||||
if (typeof params.sorts === 'string') {
|
||||
try {
|
||||
parsedSorts = JSON.parse(params.sorts)
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid JSON for sorts: ${(e as Error).message}`)
|
||||
}
|
||||
}
|
||||
if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {
|
||||
body.sorts = parsedSorts
|
||||
}
|
||||
}
|
||||
if (params.query) {
|
||||
body.query = params.query
|
||||
}
|
||||
if (params.properties && params.properties.length > 0) {
|
||||
body.properties = params.properties
|
||||
if (params.properties) {
|
||||
let parsedProperties = params.properties
|
||||
if (typeof params.properties === 'string') {
|
||||
try {
|
||||
parsedProperties = JSON.parse(params.properties)
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid JSON for properties: ${(e as Error).message}`)
|
||||
}
|
||||
}
|
||||
if (Array.isArray(parsedProperties) && parsedProperties.length > 0) {
|
||||
body.properties = parsedProperties
|
||||
}
|
||||
}
|
||||
if (params.limit) {
|
||||
body.limit = params.limit
|
||||
@@ -115,46 +145,29 @@ export const hubspotSearchContactsTool: ToolConfig<
|
||||
throw new Error(data.message || 'Failed to search contacts in HubSpot')
|
||||
}
|
||||
|
||||
const result = {
|
||||
contacts: data.results || [],
|
||||
total: data.total,
|
||||
paging: data.paging,
|
||||
metadata: {
|
||||
operation: 'search_contacts' as const,
|
||||
totalReturned: data.results?.length || 0,
|
||||
total: data.total,
|
||||
},
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
contacts: data.results || [],
|
||||
total: data.total,
|
||||
paging: data.paging,
|
||||
metadata: {
|
||||
operation: 'search_contacts' as const,
|
||||
totalReturned: data.results?.length || 0,
|
||||
total: data.total,
|
||||
},
|
||||
success: true,
|
||||
},
|
||||
output: result,
|
||||
...result,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
contacts: { type: 'array', description: 'Array of matching HubSpot contact objects' },
|
||||
total: { type: 'number', description: 'Total number of matching contacts' },
|
||||
paging: { type: 'object', description: 'Pagination information' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Search results',
|
||||
properties: {
|
||||
contacts: {
|
||||
type: 'array',
|
||||
description: 'Array of matching contact objects',
|
||||
},
|
||||
total: {
|
||||
type: 'number',
|
||||
description: 'Total number of matching contacts',
|
||||
},
|
||||
paging: {
|
||||
type: 'object',
|
||||
description: 'Pagination information',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -131,16 +131,13 @@ export interface HubSpotUpdateContactParams {
|
||||
|
||||
// Search Contacts
|
||||
export interface HubSpotSearchContactsResponse extends ToolResponse {
|
||||
output: {
|
||||
contacts: HubSpotContact[]
|
||||
contacts: HubSpotContact[]
|
||||
total: number
|
||||
paging?: HubSpotPaging
|
||||
metadata: {
|
||||
operation: 'search_contacts'
|
||||
totalReturned: number
|
||||
total: number
|
||||
paging?: HubSpotPaging
|
||||
metadata: {
|
||||
operation: 'search_contacts'
|
||||
totalReturned: number
|
||||
total: number
|
||||
}
|
||||
success: boolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,17 +209,14 @@ export type HubSpotUpdateCompanyResponse = Omit<HubSpotUpdateContactResponse, 'o
|
||||
}
|
||||
}
|
||||
export type HubSpotSearchCompaniesParams = HubSpotSearchContactsParams
|
||||
export type HubSpotSearchCompaniesResponse = Omit<HubSpotSearchContactsResponse, 'output'> & {
|
||||
output: {
|
||||
companies: HubSpotContact[]
|
||||
export interface HubSpotSearchCompaniesResponse extends ToolResponse {
|
||||
companies: HubSpotContact[]
|
||||
total: number
|
||||
paging?: HubSpotPaging
|
||||
metadata: {
|
||||
operation: 'search_companies'
|
||||
totalReturned: number
|
||||
total: number
|
||||
paging?: HubSpotPaging
|
||||
metadata: {
|
||||
operation: 'search_companies'
|
||||
totalReturned: number
|
||||
total: number
|
||||
}
|
||||
success: boolean
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,17 @@ export const hubspotUpdateCompanyTool: ToolConfig<
|
||||
}
|
||||
},
|
||||
body: (params) => {
|
||||
let properties = params.properties
|
||||
if (typeof properties === 'string') {
|
||||
try {
|
||||
properties = JSON.parse(properties)
|
||||
} catch (e) {
|
||||
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
properties: params.properties,
|
||||
properties,
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -97,21 +106,8 @@ export const hubspotUpdateCompanyTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
company: { type: 'object', description: 'Updated HubSpot company object' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Updated company data',
|
||||
properties: {
|
||||
company: {
|
||||
type: 'object',
|
||||
description: 'Updated company object with properties',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -69,8 +69,17 @@ export const hubspotUpdateContactTool: ToolConfig<
|
||||
}
|
||||
},
|
||||
body: (params) => {
|
||||
let properties = params.properties
|
||||
if (typeof properties === 'string') {
|
||||
try {
|
||||
properties = JSON.parse(properties)
|
||||
} catch (e) {
|
||||
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
properties: params.properties,
|
||||
properties,
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -97,21 +106,8 @@ export const hubspotUpdateContactTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
contact: { type: 'object', description: 'Updated HubSpot contact object' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Updated contact data',
|
||||
properties: {
|
||||
contact: {
|
||||
type: 'object',
|
||||
description: 'Updated contact object with properties',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -63,32 +63,25 @@ export const uploadTool: ToolConfig<OneDriveToolParams, OneDriveUploadResponse>
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
// If file is provided OR Excel file is being created, use custom API route
|
||||
const isExcelFile =
|
||||
params.mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
if (params.file || isExcelFile) {
|
||||
return '/api/tools/onedrive/upload'
|
||||
}
|
||||
|
||||
// Direct upload for text files - use Microsoft Graph API
|
||||
let fileName = params.fileName || 'untitled'
|
||||
|
||||
// For text files, ensure .txt extension
|
||||
if (!fileName.endsWith('.txt')) {
|
||||
// Remove any existing extensions and add .txt
|
||||
fileName = `${fileName.replace(/\.[^.]*$/, '')}.txt`
|
||||
}
|
||||
|
||||
// Build the proper URL based on parent folder
|
||||
const parentFolderId = params.manualFolderId || params.folderSelector
|
||||
if (parentFolderId && parentFolderId.trim() !== '') {
|
||||
return `https://graph.microsoft.com/v1.0/me/drive/items/${encodeURIComponent(parentFolderId)}:/${fileName}:/content`
|
||||
}
|
||||
// Default to root folder
|
||||
return `https://graph.microsoft.com/v1.0/me/drive/root:/${fileName}:/content`
|
||||
},
|
||||
method: (params) => {
|
||||
// Use POST for custom API route (file uploads or Excel creation), PUT for direct text upload
|
||||
const isExcelFile =
|
||||
params.mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
return params.file || isExcelFile ? 'POST' : 'PUT'
|
||||
@@ -98,11 +91,9 @@ export const uploadTool: ToolConfig<OneDriveToolParams, OneDriveUploadResponse>
|
||||
const isExcelFile =
|
||||
params.mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
|
||||
// For file uploads or Excel creation via custom API, send JSON
|
||||
if (params.file || isExcelFile) {
|
||||
headers['Content-Type'] = 'application/json'
|
||||
} else {
|
||||
// For direct text uploads, use direct PUT with access token
|
||||
headers.Authorization = `Bearer ${params.accessToken}`
|
||||
headers['Content-Type'] = 'text/plain'
|
||||
}
|
||||
@@ -112,20 +103,17 @@ export const uploadTool: ToolConfig<OneDriveToolParams, OneDriveUploadResponse>
|
||||
const isExcelFile =
|
||||
params.mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
|
||||
// For file uploads or Excel creation, send all params as JSON to custom API route
|
||||
if (params.file || isExcelFile) {
|
||||
return {
|
||||
accessToken: params.accessToken,
|
||||
fileName: params.fileName,
|
||||
file: params.file,
|
||||
folderId: params.manualFolderId || params.folderSelector,
|
||||
mimeType: params.mimeType,
|
||||
// Optional Excel content write-after-create
|
||||
values: params.values,
|
||||
...(params.mimeType && { mimeType: params.mimeType }),
|
||||
...(params.values && { values: params.values }),
|
||||
}
|
||||
}
|
||||
|
||||
// For text files, send content directly
|
||||
return (params.content || '') as unknown as Record<string, unknown>
|
||||
},
|
||||
},
|
||||
@@ -136,7 +124,6 @@ export const uploadTool: ToolConfig<OneDriveToolParams, OneDriveUploadResponse>
|
||||
const isExcelFile =
|
||||
params?.mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
|
||||
// Handle response from custom API route (for file uploads or Excel creation)
|
||||
if ((params?.file || isExcelFile) && data.success !== undefined) {
|
||||
if (!data.success) {
|
||||
throw new Error(data.error || 'Failed to upload file')
|
||||
@@ -153,7 +140,6 @@ export const uploadTool: ToolConfig<OneDriveToolParams, OneDriveUploadResponse>
|
||||
}
|
||||
}
|
||||
|
||||
// Handle response from direct Microsoft Graph API (for text-only uploads)
|
||||
const fileData = data
|
||||
|
||||
logger.info('Successfully uploaded file to OneDrive', {
|
||||
|
||||
@@ -132,21 +132,8 @@ export const pipedriveCreateActivityTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
activity: { type: 'object', description: 'The created activity object' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Created activity details',
|
||||
properties: {
|
||||
activity: {
|
||||
type: 'object',
|
||||
description: 'The created activity object',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -132,21 +132,8 @@ export const pipedriveCreateDealTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deal: { type: 'object', description: 'The created deal object' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Created deal details',
|
||||
properties: {
|
||||
deal: {
|
||||
type: 'object',
|
||||
description: 'The created deal object',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -141,21 +141,8 @@ export const pipedriveCreateLeadTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
lead: { type: 'object', description: 'The created lead object' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Created lead details',
|
||||
properties: {
|
||||
lead: {
|
||||
type: 'object',
|
||||
description: 'The created lead object',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -97,21 +97,8 @@ export const pipedriveCreateProjectTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
project: { type: 'object', description: 'The created project object' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Created project details',
|
||||
properties: {
|
||||
project: {
|
||||
type: 'object',
|
||||
description: 'The created project object',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -72,21 +72,8 @@ export const pipedriveDeleteLeadTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
data: { type: 'object', description: 'Deletion confirmation data' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Deletion result',
|
||||
properties: {
|
||||
data: {
|
||||
type: 'object',
|
||||
description: 'Deletion confirmation data',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -113,21 +113,8 @@ export const pipedriveGetActivitiesTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
activities: { type: 'array', description: 'Array of activity objects from Pipedrive' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Activities data',
|
||||
properties: {
|
||||
activities: {
|
||||
type: 'array',
|
||||
description: 'Array of activity objects from Pipedrive',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -118,44 +118,8 @@ export const pipedriveGetAllDealsTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deals: { type: 'array', description: 'Array of deal objects from Pipedrive' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Deals data and metadata',
|
||||
properties: {
|
||||
deals: {
|
||||
type: 'array',
|
||||
description: 'Array of deal objects from Pipedrive',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'Deal ID' },
|
||||
title: { type: 'string', description: 'Deal title' },
|
||||
value: { type: 'number', description: 'Deal value' },
|
||||
currency: { type: 'string', description: 'Deal currency' },
|
||||
status: { type: 'string', description: 'Deal status' },
|
||||
stage_id: { type: 'number', description: 'Stage ID' },
|
||||
pipeline_id: { type: 'number', description: 'Pipeline ID' },
|
||||
owner_id: { type: 'number', description: 'Owner user ID' },
|
||||
add_time: { type: 'string', description: 'Deal creation time' },
|
||||
update_time: { type: 'string', description: 'Deal last update time' },
|
||||
},
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
properties: {
|
||||
operation: { type: 'string', description: 'The operation performed' },
|
||||
totalItems: { type: 'number', description: 'Total number of deals returned' },
|
||||
hasMore: {
|
||||
type: 'boolean',
|
||||
description: 'Whether there are more items to fetch via pagination',
|
||||
},
|
||||
},
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -61,21 +61,8 @@ export const pipedriveGetDealTool: ToolConfig<PipedriveGetDealParams, PipedriveG
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deal: { type: 'object', description: 'Deal object with full details' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Deal details',
|
||||
properties: {
|
||||
deal: {
|
||||
type: 'object',
|
||||
description: 'Deal object with full details',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -94,21 +94,8 @@ export const pipedriveGetFilesTool: ToolConfig<PipedriveGetFilesParams, Pipedriv
|
||||
},
|
||||
|
||||
outputs: {
|
||||
files: { type: 'array', description: 'Array of file objects from Pipedrive' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Files data',
|
||||
properties: {
|
||||
files: {
|
||||
type: 'array',
|
||||
description: 'Array of file objects from Pipedrive',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -136,25 +136,9 @@ export const pipedriveGetLeadsTool: ToolConfig<PipedriveGetLeadsParams, Pipedriv
|
||||
},
|
||||
|
||||
outputs: {
|
||||
leads: { type: 'array', description: 'Array of lead objects (when listing all)' },
|
||||
lead: { type: 'object', description: 'Single lead object (when lead_id is provided)' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Leads data or single lead details',
|
||||
properties: {
|
||||
leads: {
|
||||
type: 'array',
|
||||
description: 'Array of lead objects (when listing all)',
|
||||
},
|
||||
lead: {
|
||||
type: 'object',
|
||||
description: 'Single lead object (when lead_id is provided)',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -90,21 +90,8 @@ export const pipedriveGetMailMessagesTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
messages: { type: 'array', description: 'Array of mail thread objects from Pipedrive mailbox' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Mail threads data',
|
||||
properties: {
|
||||
messages: {
|
||||
type: 'array',
|
||||
description: 'Array of mail thread objects from Pipedrive mailbox',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -77,21 +77,8 @@ export const pipedriveGetMailThreadTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
messages: { type: 'array', description: 'Array of mail message objects from the thread' },
|
||||
metadata: { type: 'object', description: 'Operation metadata including thread ID' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Mail thread messages data',
|
||||
properties: {
|
||||
messages: {
|
||||
type: 'array',
|
||||
description: 'Array of mail message objects from the thread',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata including thread ID',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -99,21 +99,8 @@ export const pipedriveGetPipelineDealsTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deals: { type: 'array', description: 'Array of deal objects from the pipeline' },
|
||||
metadata: { type: 'object', description: 'Operation metadata including pipeline ID' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Pipeline deals data',
|
||||
properties: {
|
||||
deals: {
|
||||
type: 'array',
|
||||
description: 'Array of deal objects from the pipeline',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata including pipeline ID',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -99,21 +99,8 @@ export const pipedriveGetPipelinesTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
pipelines: { type: 'array', description: 'Array of pipeline objects from Pipedrive' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Pipelines data',
|
||||
properties: {
|
||||
pipelines: {
|
||||
type: 'array',
|
||||
description: 'Array of pipeline objects from Pipedrive',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -112,25 +112,9 @@ export const pipedriveGetProjectsTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
projects: { type: 'array', description: 'Array of project objects (when listing all)' },
|
||||
project: { type: 'object', description: 'Single project object (when project_id is provided)' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Projects data or single project details',
|
||||
properties: {
|
||||
projects: {
|
||||
type: 'array',
|
||||
description: 'Array of project objects (when listing all)',
|
||||
},
|
||||
project: {
|
||||
type: 'object',
|
||||
description: 'Single project object (when project_id is provided)',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -116,21 +116,8 @@ export const pipedriveUpdateActivityTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
activity: { type: 'object', description: 'The updated activity object' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Updated activity details',
|
||||
properties: {
|
||||
activity: {
|
||||
type: 'object',
|
||||
description: 'The updated activity object',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -109,21 +109,8 @@ export const pipedriveUpdateDealTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deal: { type: 'object', description: 'The updated deal object' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Updated deal details',
|
||||
properties: {
|
||||
deal: {
|
||||
type: 'object',
|
||||
description: 'The updated deal object',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -142,21 +142,8 @@ export const pipedriveUpdateLeadTool: ToolConfig<
|
||||
},
|
||||
|
||||
outputs: {
|
||||
lead: { type: 'object', description: 'The updated lead object' },
|
||||
metadata: { type: 'object', description: 'Operation metadata' },
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
output: {
|
||||
type: 'object',
|
||||
description: 'Updated lead details',
|
||||
properties: {
|
||||
lead: {
|
||||
type: 'object',
|
||||
description: 'The updated lead object',
|
||||
},
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Operation metadata',
|
||||
},
|
||||
success: { type: 'boolean', description: 'Operation success status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ import {
|
||||
confluenceSearchTool,
|
||||
confluenceUpdateCommentTool,
|
||||
confluenceUpdateTool,
|
||||
confluenceUploadAttachmentTool,
|
||||
} from '@/tools/confluence'
|
||||
import {
|
||||
cursorAddFollowupTool,
|
||||
@@ -1807,6 +1808,7 @@ export const tools: Record<string, ToolConfig> = {
|
||||
confluence_update_comment: confluenceUpdateCommentTool,
|
||||
confluence_delete_comment: confluenceDeleteCommentTool,
|
||||
confluence_list_attachments: confluenceListAttachmentsTool,
|
||||
confluence_upload_attachment: confluenceUploadAttachmentTool,
|
||||
confluence_delete_attachment: confluenceDeleteAttachmentTool,
|
||||
confluence_list_labels: confluenceListLabelsTool,
|
||||
confluence_get_space: confluenceGetSpaceTool,
|
||||
|
||||
Reference in New Issue
Block a user