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

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
import type { ToolConfig } from '@/tools/types'
import type { BoxCopyFileParams, BoxUploadFileResponse } from './types'
import { UPLOAD_FILE_OUTPUT_PROPERTIES } from './types'
export const boxCopyFileTool: ToolConfig<BoxCopyFileParams, BoxUploadFileResponse> = {
id: 'box_copy_file',
name: 'Box Copy File',
description: 'Copy a file to another folder in Box',
version: '1.0.0',
oauth: {
required: true,
provider: 'box',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Box API',
},
fileId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the file to copy',
},
parentFolderId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the destination folder',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional new name for the copied file',
},
},
request: {
url: (params) => `https://api.box.com/2.0/files/${params.fileId.trim()}/copy`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, unknown> = {
parent: { id: params.parentFolderId.trim() },
}
if (params.name) body.name = params.name
return body
},
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.message || `Box API error: ${response.status}`)
}
return {
success: true,
output: {
id: data.id ?? '',
name: data.name ?? '',
size: data.size ?? 0,
sha1: data.sha1 ?? null,
createdAt: data.created_at ?? null,
modifiedAt: data.modified_at ?? null,
parentId: data.parent?.id ?? null,
parentName: data.parent?.name ?? null,
},
}
},
outputs: UPLOAD_FILE_OUTPUT_PROPERTIES,
}
+71
View File
@@ -0,0 +1,71 @@
import type { ToolConfig } from '@/tools/types'
import type { BoxCreateFolderParams, BoxFolderResponse } from './types'
import { FOLDER_OUTPUT_PROPERTIES } from './types'
export const boxCreateFolderTool: ToolConfig<BoxCreateFolderParams, BoxFolderResponse> = {
id: 'box_create_folder',
name: 'Box Create Folder',
description: 'Create a new folder in Box',
version: '1.0.0',
oauth: {
required: true,
provider: 'box',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Box API',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name for the new folder',
},
parentFolderId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the parent folder (use "0" for root)',
},
},
request: {
url: 'https://api.box.com/2.0/folders',
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => ({
name: params.name,
parent: { id: params.parentFolderId.trim() },
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.message || `Box API error: ${response.status}`)
}
return {
success: true,
output: {
id: data.id ?? '',
name: data.name ?? '',
createdAt: data.created_at ?? null,
modifiedAt: data.modified_at ?? null,
parentId: data.parent?.id ?? null,
parentName: data.parent?.name ?? null,
},
}
},
outputs: FOLDER_OUTPUT_PROPERTIES,
}
+57
View File
@@ -0,0 +1,57 @@
import type { ToolConfig, ToolResponse } from '@/tools/types'
import type { BoxDeleteFileParams } from './types'
export const boxDeleteFileTool: ToolConfig<BoxDeleteFileParams, ToolResponse> = {
id: 'box_delete_file',
name: 'Box Delete File',
description: 'Delete a file from Box',
version: '1.0.0',
oauth: {
required: true,
provider: 'box',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Box API',
},
fileId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the file to delete',
},
},
request: {
url: (params) => `https://api.box.com/2.0/files/${params.fileId.trim()}`,
method: 'DELETE',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response) => {
if (response.status === 204) {
return {
success: true,
output: {
deleted: true,
message: 'File deleted successfully',
},
}
}
const data = await response.json()
throw new Error(data.message || `Box API error: ${response.status}`)
},
outputs: {
deleted: { type: 'boolean', description: 'Whether the file was successfully deleted' },
message: { type: 'string', description: 'Success confirmation message' },
},
}
+68
View File
@@ -0,0 +1,68 @@
import type { ToolConfig, ToolResponse } from '@/tools/types'
import type { BoxDeleteFolderParams } from './types'
export const boxDeleteFolderTool: ToolConfig<BoxDeleteFolderParams, ToolResponse> = {
id: 'box_delete_folder',
name: 'Box Delete Folder',
description: 'Delete a folder from Box',
version: '1.0.0',
oauth: {
required: true,
provider: 'box',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Box API',
},
folderId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the folder to delete',
},
recursive: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Delete folder and all its contents recursively',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.recursive) queryParams.set('recursive', 'true')
const qs = queryParams.toString()
return `https://api.box.com/2.0/folders/${params.folderId.trim()}${qs ? `?${qs}` : ''}`
},
method: 'DELETE',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response) => {
if (response.status === 204) {
return {
success: true,
output: {
deleted: true,
message: 'Folder deleted successfully',
},
}
}
const data = await response.json()
throw new Error(data.message || `Box API error: ${response.status}`)
},
outputs: {
deleted: { type: 'boolean', description: 'Whether the folder was successfully deleted' },
message: { type: 'string', description: 'Success confirmation message' },
},
}
+87
View File
@@ -0,0 +1,87 @@
import type { ToolConfig } from '@/tools/types'
import type { BoxDownloadFileParams, BoxDownloadFileResponse } from './types'
export const boxDownloadFileTool: ToolConfig<BoxDownloadFileParams, BoxDownloadFileResponse> = {
id: 'box_download_file',
name: 'Box Download File',
description: 'Download a file from Box',
version: '1.0.0',
oauth: {
required: true,
provider: 'box',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Box API',
},
fileId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the file to download',
},
},
request: {
url: (params) => `https://api.box.com/2.0/files/${params.fileId.trim()}/content`,
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response) => {
if (response.status === 202) {
const retryAfter = response.headers.get('retry-after') || 'a few'
throw new Error(`File is not yet ready for download. Retry after ${retryAfter} seconds.`)
}
if (!response.ok) {
const errorText = await response.text()
throw new Error(errorText || `Failed to download file: ${response.status}`)
}
const contentType = response.headers.get('content-type') || 'application/octet-stream'
const contentDisposition = response.headers.get('content-disposition')
let fileName = 'download'
if (contentDisposition) {
const match = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
if (match?.[1]) {
fileName = match[1].replace(/['"]/g, '')
}
}
const arrayBuffer = await response.arrayBuffer()
const buffer = Buffer.from(arrayBuffer)
return {
success: true,
output: {
file: {
name: fileName,
mimeType: contentType,
data: buffer.toString('base64'),
size: buffer.length,
},
content: buffer.toString('base64'),
},
}
},
outputs: {
file: {
type: 'file',
description: 'Downloaded file stored in execution files',
},
content: {
type: 'string',
description: 'Base64 encoded file content',
},
},
}
+87
View File
@@ -0,0 +1,87 @@
import type { ToolConfig } from '@/tools/types'
import type { BoxFileInfoResponse, BoxGetFileInfoParams } from './types'
import { FILE_OUTPUT_PROPERTIES } from './types'
export const boxGetFileInfoTool: ToolConfig<BoxGetFileInfoParams, BoxFileInfoResponse> = {
id: 'box_get_file_info',
name: 'Box Get File Info',
description: 'Get detailed information about a file in Box',
version: '1.0.0',
oauth: {
required: true,
provider: 'box',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Box API',
},
fileId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the file to get information about',
},
},
request: {
url: (params) => `https://api.box.com/2.0/files/${params.fileId.trim()}`,
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.message || `Box API error: ${response.status}`)
}
return {
success: true,
output: {
id: data.id ?? '',
name: data.name ?? '',
description: data.description ?? null,
size: data.size ?? 0,
sha1: data.sha1 ?? null,
createdAt: data.created_at ?? null,
modifiedAt: data.modified_at ?? null,
createdBy: data.created_by
? {
id: data.created_by.id,
name: data.created_by.name,
login: data.created_by.login,
}
: null,
modifiedBy: data.modified_by
? {
id: data.modified_by.id,
name: data.modified_by.name,
login: data.modified_by.login,
}
: null,
ownedBy: data.owned_by
? {
id: data.owned_by.id,
name: data.owned_by.name,
login: data.owned_by.login,
}
: null,
parentId: data.parent?.id ?? null,
parentName: data.parent?.name ?? null,
sharedLink: data.shared_link ?? null,
tags: data.tags ?? [],
commentCount: data.comment_count ?? null,
},
}
},
outputs: FILE_OUTPUT_PROPERTIES,
}
+10
View File
@@ -0,0 +1,10 @@
export { boxCopyFileTool } from '@/tools/box/copy_file'
export { boxCreateFolderTool } from '@/tools/box/create_folder'
export { boxDeleteFileTool } from '@/tools/box/delete_file'
export { boxDeleteFolderTool } from '@/tools/box/delete_folder'
export { boxDownloadFileTool } from '@/tools/box/download_file'
export { boxGetFileInfoTool } from '@/tools/box/get_file_info'
export { boxListFolderItemsTool } from '@/tools/box/list_folder_items'
export { boxSearchTool } from '@/tools/box/search'
export { boxUpdateFileTool } from '@/tools/box/update_file'
export { boxUploadFileTool } from '@/tools/box/upload_file'
+98
View File
@@ -0,0 +1,98 @@
import type { ToolConfig } from '@/tools/types'
import type { BoxFolderItemsResponse, BoxListFolderItemsParams } from './types'
import { FOLDER_ITEMS_OUTPUT_PROPERTIES } from './types'
export const boxListFolderItemsTool: ToolConfig<BoxListFolderItemsParams, BoxFolderItemsResponse> =
{
id: 'box_list_folder_items',
name: 'Box List Folder Items',
description: 'List files and folders in a Box folder',
version: '1.0.0',
oauth: {
required: true,
provider: 'box',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Box API',
},
folderId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the folder to list items from (use "0" for root)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of items to return per page',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'The offset for pagination',
},
sort: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Sort field: id, name, date, or size',
},
direction: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Sort direction: ASC or DESC',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.limit !== undefined) queryParams.set('limit', String(params.limit))
if (params.offset !== undefined) queryParams.set('offset', String(params.offset))
if (params.sort) queryParams.set('sort', params.sort)
if (params.direction) queryParams.set('direction', params.direction)
const qs = queryParams.toString()
return `https://api.box.com/2.0/folders/${params.folderId.trim()}/items${qs ? `?${qs}` : ''}`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.message || `Box API error: ${response.status}`)
}
return {
success: true,
output: {
entries: (data.entries ?? []).map((item: Record<string, unknown>) => ({
type: item.type ?? '',
id: item.id ?? '',
name: item.name ?? '',
size: item.size ?? null,
createdAt: item.created_at ?? null,
modifiedAt: item.modified_at ?? null,
})),
totalCount: data.total_count ?? 0,
offset: data.offset ?? 0,
limit: data.limit ?? 0,
},
}
},
outputs: FOLDER_ITEMS_OUTPUT_PROPERTIES,
}
+105
View File
@@ -0,0 +1,105 @@
import type { ToolConfig } from '@/tools/types'
import type { BoxSearchParams, BoxSearchResponse } from './types'
import { SEARCH_RESULT_OUTPUT_PROPERTIES } from './types'
export const boxSearchTool: ToolConfig<BoxSearchParams, BoxSearchResponse> = {
id: 'box_search',
name: 'Box Search',
description: 'Search for files and folders in Box',
version: '1.0.0',
oauth: {
required: true,
provider: 'box',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Box API',
},
query: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The search query string',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'The offset for pagination',
},
ancestorFolderId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Restrict search to a specific folder and its subfolders',
},
fileExtensions: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated file extensions to filter by (e.g., pdf,docx)',
},
type: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Restrict to a specific content type: file, folder, or web_link',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
queryParams.set('query', params.query)
if (params.limit !== undefined) queryParams.set('limit', String(params.limit))
if (params.offset !== undefined) queryParams.set('offset', String(params.offset))
if (params.ancestorFolderId)
queryParams.set('ancestor_folder_ids', params.ancestorFolderId.trim())
if (params.fileExtensions) queryParams.set('file_extensions', params.fileExtensions)
if (params.type) queryParams.set('type', params.type)
return `https://api.box.com/2.0/search?${queryParams.toString()}`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.message || `Box API error: ${response.status}`)
}
return {
success: true,
output: {
results: (data.entries ?? []).map((item: Record<string, unknown>) => ({
type: item.type ?? '',
id: item.id ?? '',
name: item.name ?? '',
size: item.size ?? null,
createdAt: item.created_at ?? null,
modifiedAt: item.modified_at ?? null,
parentId: (item.parent as Record<string, unknown> | undefined)?.id ?? null,
parentName: (item.parent as Record<string, unknown> | undefined)?.name ?? null,
})),
totalCount: data.total_count ?? 0,
},
}
},
outputs: SEARCH_RESULT_OUTPUT_PROPERTIES,
}
+249
View File
@@ -0,0 +1,249 @@
import type { OutputProperty, ToolResponse } from '@/tools/types'
export interface BoxUploadFileParams {
accessToken: string
parentFolderId: string
file?: unknown
fileContent?: string
fileName?: string
}
export interface BoxDownloadFileParams {
accessToken: string
fileId: string
}
export interface BoxGetFileInfoParams {
accessToken: string
fileId: string
}
export interface BoxListFolderItemsParams {
accessToken: string
folderId: string
limit?: number
offset?: number
sort?: string
direction?: string
}
export interface BoxCreateFolderParams {
accessToken: string
name: string
parentFolderId: string
}
export interface BoxDeleteFileParams {
accessToken: string
fileId: string
}
export interface BoxDeleteFolderParams {
accessToken: string
folderId: string
recursive?: boolean
}
export interface BoxCopyFileParams {
accessToken: string
fileId: string
parentFolderId: string
name?: string
}
export interface BoxSearchParams {
accessToken: string
query: string
limit?: number
offset?: number
ancestorFolderId?: string
fileExtensions?: string
type?: string
}
export interface BoxUpdateFileParams {
accessToken: string
fileId: string
name?: string
description?: string
parentFolderId?: string
tags?: string
}
export interface BoxUploadFileResponse extends ToolResponse {
output: {
id: string
name: string
size: number
sha1: string | null
createdAt: string | null
modifiedAt: string | null
parentId: string | null
parentName: string | null
}
}
export interface BoxDownloadFileResponse extends ToolResponse {
output: {
file: {
name: string
mimeType: string
data: string
size: number
}
content: string
}
}
export interface BoxFileInfoResponse extends ToolResponse {
output: {
id: string
name: string
description: string | null
size: number
sha1: string | null
createdAt: string | null
modifiedAt: string | null
createdBy: { id: string; name: string; login: string } | null
modifiedBy: { id: string; name: string; login: string } | null
ownedBy: { id: string; name: string; login: string } | null
parentId: string | null
parentName: string | null
sharedLink: Record<string, unknown> | null
tags: string[]
commentCount: number | null
}
}
export interface BoxFolderItemsResponse extends ToolResponse {
output: {
entries: Array<Record<string, unknown>>
totalCount: number
offset: number
limit: number
}
}
export interface BoxFolderResponse extends ToolResponse {
output: {
id: string
name: string
createdAt: string | null
modifiedAt: string | null
parentId: string | null
parentName: string | null
}
}
export interface BoxSearchResponse extends ToolResponse {
output: {
results: Array<Record<string, unknown>>
totalCount: number
}
}
const USER_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'User ID' },
name: { type: 'string', description: 'User name' },
login: { type: 'string', description: 'User email/login' },
} as const satisfies Record<string, OutputProperty>
export const FILE_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'File ID' },
name: { type: 'string', description: 'File name' },
description: { type: 'string', description: 'File description', optional: true },
size: { type: 'number', description: 'File size in bytes' },
sha1: { type: 'string', description: 'SHA1 hash of file content', optional: true },
createdAt: { type: 'string', description: 'Creation timestamp', optional: true },
modifiedAt: { type: 'string', description: 'Last modified timestamp', optional: true },
createdBy: {
type: 'object',
description: 'User who created the file',
optional: true,
properties: USER_OUTPUT_PROPERTIES,
},
modifiedBy: {
type: 'object',
description: 'User who last modified the file',
optional: true,
properties: USER_OUTPUT_PROPERTIES,
},
ownedBy: {
type: 'object',
description: 'User who owns the file',
optional: true,
properties: USER_OUTPUT_PROPERTIES,
},
parentId: { type: 'string', description: 'Parent folder ID', optional: true },
parentName: { type: 'string', description: 'Parent folder name', optional: true },
sharedLink: { type: 'json', description: 'Shared link details', optional: true },
tags: {
type: 'array',
description: 'File tags',
items: { type: 'string' },
optional: true,
},
commentCount: { type: 'number', description: 'Number of comments', optional: true },
} as const satisfies Record<string, OutputProperty>
export const FOLDER_ITEMS_OUTPUT_PROPERTIES = {
entries: {
type: 'array',
description: 'List of items in the folder',
items: {
type: 'object',
properties: {
type: { type: 'string', description: 'Item type (file, folder, web_link)' },
id: { type: 'string', description: 'Item ID' },
name: { type: 'string', description: 'Item name' },
size: { type: 'number', description: 'Item size in bytes', optional: true },
createdAt: { type: 'string', description: 'Creation timestamp', optional: true },
modifiedAt: { type: 'string', description: 'Last modified timestamp', optional: true },
},
},
},
totalCount: { type: 'number', description: 'Total number of items in the folder' },
offset: { type: 'number', description: 'Current pagination offset' },
limit: { type: 'number', description: 'Current pagination limit' },
} as const satisfies Record<string, OutputProperty>
export const FOLDER_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'Folder ID' },
name: { type: 'string', description: 'Folder name' },
createdAt: { type: 'string', description: 'Creation timestamp', optional: true },
modifiedAt: { type: 'string', description: 'Last modified timestamp', optional: true },
parentId: { type: 'string', description: 'Parent folder ID', optional: true },
parentName: { type: 'string', description: 'Parent folder name', optional: true },
} as const satisfies Record<string, OutputProperty>
export const SEARCH_RESULT_OUTPUT_PROPERTIES = {
results: {
type: 'array',
description: 'Search results',
items: {
type: 'object',
properties: {
type: { type: 'string', description: 'Item type (file, folder, web_link)' },
id: { type: 'string', description: 'Item ID' },
name: { type: 'string', description: 'Item name' },
size: { type: 'number', description: 'Item size in bytes', optional: true },
createdAt: { type: 'string', description: 'Creation timestamp', optional: true },
modifiedAt: { type: 'string', description: 'Last modified timestamp', optional: true },
parentId: { type: 'string', description: 'Parent folder ID', optional: true },
parentName: { type: 'string', description: 'Parent folder name', optional: true },
},
},
},
totalCount: { type: 'number', description: 'Total number of matching results' },
} as const satisfies Record<string, OutputProperty>
export const UPLOAD_FILE_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'File ID' },
name: { type: 'string', description: 'File name' },
size: { type: 'number', description: 'File size in bytes' },
sha1: { type: 'string', description: 'SHA1 hash of file content', optional: true },
createdAt: { type: 'string', description: 'Creation timestamp', optional: true },
modifiedAt: { type: 'string', description: 'Last modified timestamp', optional: true },
parentId: { type: 'string', description: 'Parent folder ID', optional: true },
parentName: { type: 'string', description: 'Parent folder name', optional: true },
} as const satisfies Record<string, OutputProperty>
+124
View File
@@ -0,0 +1,124 @@
import type { ToolConfig } from '@/tools/types'
import type { BoxFileInfoResponse, BoxUpdateFileParams } from './types'
import { FILE_OUTPUT_PROPERTIES } from './types'
export const boxUpdateFileTool: ToolConfig<BoxUpdateFileParams, BoxFileInfoResponse> = {
id: 'box_update_file',
name: 'Box Update File',
description: 'Update file info in Box (rename, move, change description, add tags)',
version: '1.0.0',
oauth: {
required: true,
provider: 'box',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Box API',
},
fileId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the file to update',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'New name for the file',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'New description for the file (max 256 characters)',
},
parentFolderId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Move the file to a different folder by specifying the folder ID',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated tags to set on the file',
},
},
request: {
url: (params) => `https://api.box.com/2.0/files/${params.fileId.trim()}`,
method: 'PUT',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, unknown> = {}
if (params.name) body.name = params.name
if (params.description !== undefined) body.description = params.description
if (params.parentFolderId) body.parent = { id: params.parentFolderId.trim() }
if (params.tags)
body.tags = params.tags
.split(',')
.map((t: string) => t.trim())
.filter(Boolean)
return body
},
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.message || `Box API error: ${response.status}`)
}
return {
success: true,
output: {
id: data.id ?? '',
name: data.name ?? '',
description: data.description ?? null,
size: data.size ?? 0,
sha1: data.sha1 ?? null,
createdAt: data.created_at ?? null,
modifiedAt: data.modified_at ?? null,
createdBy: data.created_by
? {
id: data.created_by.id,
name: data.created_by.name,
login: data.created_by.login,
}
: null,
modifiedBy: data.modified_by
? {
id: data.modified_by.id,
name: data.modified_by.name,
login: data.modified_by.login,
}
: null,
ownedBy: data.owned_by
? {
id: data.owned_by.id,
name: data.owned_by.name,
login: data.owned_by.login,
}
: null,
parentId: data.parent?.id ?? null,
parentName: data.parent?.name ?? null,
sharedLink: data.shared_link ?? null,
tags: data.tags ?? [],
commentCount: data.comment_count ?? null,
},
}
},
outputs: FILE_OUTPUT_PROPERTIES,
}
+78
View File
@@ -0,0 +1,78 @@
import type { ToolConfig } from '@/tools/types'
import type { BoxUploadFileParams, BoxUploadFileResponse } from './types'
import { UPLOAD_FILE_OUTPUT_PROPERTIES } from './types'
export const boxUploadFileTool: ToolConfig<BoxUploadFileParams, BoxUploadFileResponse> = {
id: 'box_upload_file',
name: 'Box Upload File',
description: 'Upload a file to a Box folder',
version: '1.0.0',
oauth: {
required: true,
provider: 'box',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Box API',
},
parentFolderId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the folder to upload the file to (use "0" for root)',
},
file: {
type: 'file',
required: false,
visibility: 'user-or-llm',
description: 'The file to upload (UserFile object)',
},
fileContent: {
type: 'string',
required: false,
visibility: 'hidden',
description: 'Legacy: base64 encoded file content',
},
fileName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional filename override',
},
},
request: {
url: '/api/tools/box/upload',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
parentFolderId: params.parentFolderId,
file: params.file,
fileContent: params.fileContent,
fileName: params.fileName,
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (!data.success) {
throw new Error(data.error || 'Failed to upload file')
}
return {
success: true,
output: data.output,
}
},
outputs: UPLOAD_FILE_OUTPUT_PROPERTIES,
}