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
+87
View File
@@ -0,0 +1,87 @@
import type { DropboxCopyParams, DropboxCopyResponse } from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxCopyTool: ToolConfig<DropboxCopyParams, DropboxCopyResponse> = {
id: 'dropbox_copy',
name: 'Dropbox Copy',
description: 'Copy a file or folder in Dropbox',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
fromPath: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The source path of the file or folder to copy',
},
toPath: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The destination path for the copied file or folder',
},
autorename: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'If true, rename the file if there is a conflict at destination',
},
},
request: {
url: 'https://api.dropboxapi.com/2/files/copy_v2',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Dropbox API request')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => ({
from_path: params.fromPath.trim(),
to_path: params.toPath.trim(),
autorename: params.autorename ?? false,
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
return {
success: false,
error: data.error_summary || data.error?.message || 'Failed to copy file/folder',
output: {},
}
}
return {
success: true,
output: {
metadata: data.metadata,
},
}
},
outputs: {
metadata: {
type: 'object',
description: 'Metadata of the copied item',
properties: {
'.tag': { type: 'string', description: 'Type: file or folder' },
id: { type: 'string', description: 'Unique identifier', optional: true },
name: { type: 'string', description: 'Name of the copied item' },
path_display: { type: 'string', description: 'Display path', optional: true },
size: { type: 'number', description: 'Size in bytes (files only)', optional: true },
},
},
},
}
+82
View File
@@ -0,0 +1,82 @@
import type { DropboxCreateFolderParams, DropboxCreateFolderResponse } from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxCreateFolderTool: ToolConfig<
DropboxCreateFolderParams,
DropboxCreateFolderResponse
> = {
id: 'dropbox_create_folder',
name: 'Dropbox Create Folder',
description: 'Create a new folder in Dropbox',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
path: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The path where the folder should be created (e.g., /new-folder)',
},
autorename: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'If true, rename the folder if there is a conflict',
},
},
request: {
url: 'https://api.dropboxapi.com/2/files/create_folder_v2',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Dropbox API request')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => ({
path: params.path.trim(),
autorename: params.autorename ?? false,
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
return {
success: false,
error: data.error_summary || data.error?.message || 'Failed to create folder',
output: {},
}
}
return {
success: true,
output: {
folder: data.metadata,
},
}
},
outputs: {
folder: {
type: 'object',
description: 'The created folder metadata',
properties: {
id: { type: 'string', description: 'Unique identifier for the folder' },
name: { type: 'string', description: 'Name of the folder' },
path_display: { type: 'string', description: 'Display path of the folder', optional: true },
path_lower: { type: 'string', description: 'Lowercase path of the folder', optional: true },
},
},
},
}
@@ -0,0 +1,147 @@
import type {
DropboxCreateSharedLinkParams,
DropboxCreateSharedLinkResponse,
} from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxCreateSharedLinkTool: ToolConfig<
DropboxCreateSharedLinkParams,
DropboxCreateSharedLinkResponse
> = {
id: 'dropbox_create_shared_link',
name: 'Dropbox Create Shared Link',
description: 'Create a shareable link for a file or folder in Dropbox',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
path: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The path of the file or folder to share',
},
requestedVisibility: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Visibility: public, team_only, or password',
},
linkPassword: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for the shared link (only if visibility is password)',
},
expires: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Expiration date in ISO 8601 format (e.g., 2025-12-31T23:59:59Z)',
},
},
request: {
url: 'https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Dropbox API request')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
const body: Record<string, any> = {
path: params.path.trim(),
}
const settings: Record<string, any> = {}
if (params.requestedVisibility) {
settings.requested_visibility = { '.tag': params.requestedVisibility }
}
if (params.linkPassword) {
settings.link_password = params.linkPassword
}
if (params.expires) {
settings.expires = params.expires
}
if (Object.keys(settings).length > 0) {
body.settings = settings
}
return body
},
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
// A link may already exist for this path - Dropbox includes its metadata in the error
// when the requested settings match the existing link, so surface it as a success.
// Per Stone's JSON rules, a union member whose payload is a struct (SharedLinkMetadata)
// flattens that struct's fields alongside ".tag" - there is no nested "metadata" key.
const existingLink = data.error?.shared_link_already_exists
if (existingLink) {
return {
success: true,
output: {
sharedLink: existingLink,
},
}
}
if (data.error_summary?.includes('shared_link_already_exists')) {
return {
success: false,
error:
'A shared link already exists for this path with different settings. Use Dropbox List Shared Links to retrieve it.',
output: {},
}
}
return {
success: false,
error: data.error_summary || data.error?.message || 'Failed to create shared link',
output: {},
}
}
return {
success: true,
output: {
sharedLink: data,
},
}
},
outputs: {
sharedLink: {
type: 'object',
description: 'The created shared link',
properties: {
url: { type: 'string', description: 'The shared link URL' },
name: { type: 'string', description: 'Name of the shared item' },
path_lower: {
type: 'string',
description: 'Lowercase path of the shared item',
optional: true,
},
expires: { type: 'string', description: 'Expiration date if set', optional: true },
link_permissions: {
type: 'object',
description: 'Permissions for the shared link',
},
},
},
},
}
+76
View File
@@ -0,0 +1,76 @@
import type { DropboxDeleteParams, DropboxDeleteResponse } from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxDeleteTool: ToolConfig<DropboxDeleteParams, DropboxDeleteResponse> = {
id: 'dropbox_delete',
name: 'Dropbox Delete',
description: 'Delete a file or folder in Dropbox (moves to trash)',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
path: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The path of the file or folder to delete',
},
},
request: {
url: 'https://api.dropboxapi.com/2/files/delete_v2',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Dropbox API request')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => ({
path: params.path.trim(),
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
return {
success: false,
error: data.error_summary || data.error?.message || 'Failed to delete file/folder',
output: {},
}
}
return {
success: true,
output: {
metadata: data.metadata,
deleted: true,
},
}
},
outputs: {
metadata: {
type: 'object',
description: 'Metadata of the deleted item',
properties: {
'.tag': { type: 'string', description: 'Type: file, folder, or deleted' },
name: { type: 'string', description: 'Name of the deleted item' },
path_display: { type: 'string', description: 'Display path', optional: true },
},
},
deleted: {
type: 'boolean',
description: 'Whether the deletion was successful',
},
},
}
+112
View File
@@ -0,0 +1,112 @@
import { httpHeaderSafeJson } from '@/lib/core/utils/validation'
import type { DropboxDownloadParams, DropboxDownloadResponse } from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxDownloadTool: ToolConfig<DropboxDownloadParams, DropboxDownloadResponse> = {
id: 'dropbox_download',
name: 'Dropbox Download File',
description: 'Download a file from Dropbox with metadata and content',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
path: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The path of the file to download (e.g., /folder/document.pdf)',
},
},
request: {
url: 'https://content.dropboxapi.com/2/files/download',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Dropbox API request')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/octet-stream',
'Dropbox-API-Arg': httpHeaderSafeJson({ path: params.path.trim() }),
}
},
},
transformResponse: async (response, params) => {
if (!response.ok) {
const errorText = await response.text()
return {
success: false,
error: errorText || 'Failed to download file',
output: {},
}
}
const apiResultHeader =
response.headers.get('dropbox-api-result') || response.headers.get('Dropbox-API-Result')
const metadata = apiResultHeader ? JSON.parse(apiResultHeader) : undefined
const contentType = response.headers.get('content-type') || 'application/octet-stream'
const arrayBuffer = await response.arrayBuffer()
const buffer = Buffer.from(arrayBuffer)
const resolvedName = metadata?.name || params?.path?.split('/').pop() || 'download'
let temporaryLink: string | undefined
if (params?.accessToken) {
try {
const linkResponse = await fetch('https://api.dropboxapi.com/2/files/get_temporary_link', {
method: 'POST',
headers: {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ path: params.path.trim() }),
})
if (linkResponse.ok) {
const linkData = await linkResponse.json()
temporaryLink = linkData.link
}
} catch {
temporaryLink = undefined
}
}
return {
success: true,
output: {
file: {
name: resolvedName,
mimeType: contentType,
data: buffer.toString('base64'),
size: buffer.length,
},
content: buffer.toString('base64'),
metadata,
temporaryLink,
},
}
},
outputs: {
file: {
type: 'file',
description: 'Downloaded file stored in execution files',
},
metadata: {
type: 'json',
description: 'The file metadata',
},
temporaryLink: {
type: 'string',
description: 'Temporary link to download the file (valid for ~4 hours)',
},
content: {
type: 'string',
description: 'Base64 encoded file content (if fetched)',
},
},
}
+107
View File
@@ -0,0 +1,107 @@
import type { DropboxGetMetadataParams, DropboxGetMetadataResponse } from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxGetMetadataTool: ToolConfig<
DropboxGetMetadataParams,
DropboxGetMetadataResponse
> = {
id: 'dropbox_get_metadata',
name: 'Dropbox Get Metadata',
description: 'Get metadata for a file or folder in Dropbox',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
path: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The path of the file or folder to get metadata for',
},
includeMediaInfo: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'If true, include media info for photos/videos',
},
includeDeleted: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'If true, include deleted files in results',
},
},
request: {
url: 'https://api.dropboxapi.com/2/files/get_metadata',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Dropbox API request')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => ({
path: params.path.trim(),
include_media_info: params.includeMediaInfo ?? false,
include_deleted: params.includeDeleted ?? false,
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
return {
success: false,
error: data.error_summary || data.error?.message || 'Failed to get metadata',
output: {},
}
}
return {
success: true,
output: {
metadata: data,
},
}
},
outputs: {
metadata: {
type: 'object',
description: 'Metadata for the file or folder',
properties: {
'.tag': { type: 'string', description: 'Type: file, folder, or deleted' },
id: { type: 'string', description: 'Unique identifier', optional: true },
name: { type: 'string', description: 'Name of the item' },
path_display: { type: 'string', description: 'Display path', optional: true },
path_lower: { type: 'string', description: 'Lowercase path', optional: true },
size: { type: 'number', description: 'Size in bytes (files only)', optional: true },
client_modified: {
type: 'string',
description: 'Client modification time (files only)',
optional: true,
},
server_modified: {
type: 'string',
description: 'Server modification time (files only)',
optional: true,
},
rev: { type: 'string', description: 'Revision identifier (files only)', optional: true },
content_hash: {
type: 'string',
description: 'Content hash (files only)',
optional: true,
},
},
},
},
}
+29
View File
@@ -0,0 +1,29 @@
import { dropboxCopyTool } from '@/tools/dropbox/copy'
import { dropboxCreateFolderTool } from '@/tools/dropbox/create_folder'
import { dropboxCreateSharedLinkTool } from '@/tools/dropbox/create_shared_link'
import { dropboxDeleteTool } from '@/tools/dropbox/delete'
import { dropboxDownloadTool } from '@/tools/dropbox/download'
import { dropboxGetMetadataTool } from '@/tools/dropbox/get_metadata'
import { dropboxListFolderTool } from '@/tools/dropbox/list_folder'
import { dropboxListRevisionsTool } from '@/tools/dropbox/list_revisions'
import { dropboxListSharedLinksTool } from '@/tools/dropbox/list_shared_links'
import { dropboxMoveTool } from '@/tools/dropbox/move'
import { dropboxRestoreTool } from '@/tools/dropbox/restore'
import { dropboxSearchTool } from '@/tools/dropbox/search'
import { dropboxUploadTool } from '@/tools/dropbox/upload'
export {
dropboxCopyTool,
dropboxCreateFolderTool,
dropboxCreateSharedLinkTool,
dropboxDeleteTool,
dropboxDownloadTool,
dropboxGetMetadataTool,
dropboxListFolderTool,
dropboxListRevisionsTool,
dropboxListSharedLinksTool,
dropboxMoveTool,
dropboxRestoreTool,
dropboxSearchTool,
dropboxUploadTool,
}
+115
View File
@@ -0,0 +1,115 @@
import type { DropboxListFolderParams, DropboxListFolderResponse } from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxListFolderTool: ToolConfig<DropboxListFolderParams, DropboxListFolderResponse> =
{
id: 'dropbox_list_folder',
name: 'Dropbox List Folder',
description: 'List the contents of a folder in Dropbox',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
path: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The path of the folder to list (use "" for root)',
},
recursive: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'If true, list contents recursively',
},
includeDeleted: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'If true, include deleted files/folders',
},
includeMediaInfo: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'If true, include media info for photos/videos',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return (default: 500)',
},
},
request: {
url: 'https://api.dropboxapi.com/2/files/list_folder',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Dropbox API request')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => ({
path: params.path.trim() === '/' ? '' : params.path.trim(),
recursive: params.recursive ?? false,
include_deleted: params.includeDeleted ?? false,
include_media_info: params.includeMediaInfo ?? false,
limit: params.limit,
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
return {
success: false,
error: data.error_summary || data.error?.message || 'Failed to list folder',
output: {},
}
}
return {
success: true,
output: {
entries: data.entries,
cursor: data.cursor,
hasMore: data.has_more,
},
}
},
outputs: {
entries: {
type: 'array',
description: 'List of files and folders in the directory',
items: {
type: 'object',
properties: {
'.tag': { type: 'string', description: 'Type: file, folder, or deleted' },
id: { type: 'string', description: 'Unique identifier', optional: true },
name: { type: 'string', description: 'Name of the file/folder' },
path_display: { type: 'string', description: 'Display path', optional: true },
size: { type: 'number', description: 'Size in bytes (files only)', optional: true },
},
},
},
cursor: {
type: 'string',
description: 'Cursor for pagination',
},
hasMore: {
type: 'boolean',
description: 'Whether there are more results',
},
},
}
+114
View File
@@ -0,0 +1,114 @@
import type {
DropboxListRevisionsParams,
DropboxListRevisionsResponse,
} from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxListRevisionsTool: ToolConfig<
DropboxListRevisionsParams,
DropboxListRevisionsResponse
> = {
id: 'dropbox_list_revisions',
name: 'Dropbox List Revisions',
description: 'List the revision history for a file in Dropbox (files only, not folders)',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
path: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The path of the file to list revisions for',
},
limit: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Maximum number of revisions to return, 1-100 (default: 10)',
},
beforeRev: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'Only return revisions before this one. Pass the rev of the last revision from a previous call to fetch the next page.',
},
},
request: {
url: 'https://api.dropboxapi.com/2/files/list_revisions',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Dropbox API request')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
const body: Record<string, any> = {
path: params.path.trim(),
mode: 'path',
limit: params.limit ?? 10,
}
if (params.beforeRev) {
body.before_rev = params.beforeRev.trim()
}
return body
},
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
return {
success: false,
error: data.error_summary || data.error?.message || 'Failed to list revisions',
output: {},
}
}
return {
success: true,
output: {
entries: data.entries || [],
isDeleted: data.is_deleted ?? false,
hasMore: data.has_more ?? false,
},
}
},
outputs: {
entries: {
type: 'array',
description: 'The revisions for the file, most recent first',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique identifier for this revision' },
name: { type: 'string', description: 'Name of the file' },
path_display: { type: 'string', description: 'Display path', optional: true },
rev: { type: 'string', description: 'Revision identifier, pass to Restore' },
size: { type: 'number', description: 'Size of this revision in bytes' },
server_modified: { type: 'string', description: 'Server modification time' },
},
},
},
isDeleted: {
type: 'boolean',
description: 'Whether the file identified by the latest revision is deleted or moved',
},
hasMore: {
type: 'boolean',
description: 'Whether there are more revisions available',
},
},
}
+120
View File
@@ -0,0 +1,120 @@
import type {
DropboxListSharedLinksParams,
DropboxListSharedLinksResponse,
} from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxListSharedLinksTool: ToolConfig<
DropboxListSharedLinksParams,
DropboxListSharedLinksResponse
> = {
id: 'dropbox_list_shared_links',
name: 'Dropbox List Shared Links',
description: 'List shared links for a path, or for the entire account if no path is given',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
path: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Path to list shared links for. If omitted, lists all shared links.',
},
directOnly: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'If true, only return links directly to the path, not parent folder links',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Cursor from a previous call to fetch the next page of results',
},
},
request: {
url: 'https://api.dropboxapi.com/2/sharing/list_shared_links',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Dropbox API request')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
const body: Record<string, any> = {}
if (params.path) {
const trimmedPath = params.path.trim()
// Dropbox only returns every shared link on the account when `path` is omitted
// entirely; sending "" scopes the results to the root folder instead. Since our UI
// tells users "/" means "list all links", omit the field rather than sending "".
if (trimmedPath !== '/' && trimmedPath !== '') {
body.path = trimmedPath
}
}
if (params.directOnly !== undefined) body.direct_only = params.directOnly
if (params.cursor) body.cursor = params.cursor
return body
},
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
return {
success: false,
error: data.error_summary || data.error?.message || 'Failed to list shared links',
output: {},
}
}
return {
success: true,
output: {
links: data.links ?? [],
hasMore: data.has_more ?? false,
cursor: data.cursor,
},
}
},
outputs: {
links: {
type: 'array',
description: 'Shared links applicable to the path argument',
items: {
type: 'object',
properties: {
'.tag': { type: 'string', description: 'Type: file or folder' },
url: { type: 'string', description: 'The shared link URL' },
name: { type: 'string', description: 'Name of the shared item' },
path_lower: {
type: 'string',
description: 'Lowercase path of the shared item',
optional: true,
},
expires: { type: 'string', description: 'Expiration date if set', optional: true },
},
},
},
hasMore: {
type: 'boolean',
description: 'Whether there are more results',
},
cursor: {
type: 'string',
description: 'Cursor for pagination (only returned when no path is given)',
},
},
}
+87
View File
@@ -0,0 +1,87 @@
import type { DropboxMoveParams, DropboxMoveResponse } from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxMoveTool: ToolConfig<DropboxMoveParams, DropboxMoveResponse> = {
id: 'dropbox_move',
name: 'Dropbox Move',
description: 'Move or rename a file or folder in Dropbox',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
fromPath: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The source path of the file or folder to move',
},
toPath: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The destination path for the moved file or folder',
},
autorename: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'If true, rename the file if there is a conflict at destination',
},
},
request: {
url: 'https://api.dropboxapi.com/2/files/move_v2',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Dropbox API request')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => ({
from_path: params.fromPath.trim(),
to_path: params.toPath.trim(),
autorename: params.autorename ?? false,
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
return {
success: false,
error: data.error_summary || data.error?.message || 'Failed to move file/folder',
output: {},
}
}
return {
success: true,
output: {
metadata: data.metadata,
},
}
},
outputs: {
metadata: {
type: 'object',
description: 'Metadata of the moved item',
properties: {
'.tag': { type: 'string', description: 'Type: file or folder' },
id: { type: 'string', description: 'Unique identifier', optional: true },
name: { type: 'string', description: 'Name of the moved item' },
path_display: { type: 'string', description: 'Display path', optional: true },
size: { type: 'number', description: 'Size in bytes (files only)', optional: true },
},
},
},
}
+82
View File
@@ -0,0 +1,82 @@
import type { DropboxRestoreParams, DropboxRestoreResponse } from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxRestoreTool: ToolConfig<DropboxRestoreParams, DropboxRestoreResponse> = {
id: 'dropbox_restore',
name: 'Dropbox Restore',
description: 'Restore a specific revision of a file to the given path',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
path: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The path to save the restored file to',
},
rev: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The revision identifier to restore (from Dropbox List Revisions)',
},
},
request: {
url: 'https://api.dropboxapi.com/2/files/restore',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Dropbox API request')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => ({
path: params.path.trim(),
rev: params.rev.trim(),
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
return {
success: false,
error: data.error_summary || data.error?.message || 'Failed to restore file',
output: {},
}
}
return {
success: true,
output: {
metadata: data,
},
}
},
outputs: {
metadata: {
type: 'object',
description: 'Metadata of the restored file',
properties: {
id: { type: 'string', description: 'Unique identifier for the file' },
name: { type: 'string', description: 'Name of the file' },
path_display: { type: 'string', description: 'Display path of the file', optional: true },
path_lower: { type: 'string', description: 'Lowercase path of the file', optional: true },
size: { type: 'number', description: 'Size of the file in bytes' },
rev: { type: 'string', description: 'Revision identifier of the restored file' },
server_modified: { type: 'string', description: 'Server modification time' },
},
},
},
}
+136
View File
@@ -0,0 +1,136 @@
import type { DropboxSearchParams, DropboxSearchResponse } from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxSearchTool: ToolConfig<DropboxSearchParams, DropboxSearchResponse> = {
id: 'dropbox_search',
name: 'Dropbox Search',
description: 'Search for files and folders in Dropbox',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
query: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The search query',
},
path: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Dropbox folder path to limit search scope (e.g., /folder/subfolder)',
},
fileExtensions: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Comma-separated list of file extensions to filter by (e.g., pdf,xlsx)',
},
maxResults: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return (default: 100)',
},
},
request: {
url: 'https://api.dropboxapi.com/2/files/search_v2',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Dropbox API request')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
const body: Record<string, any> = {
query: params.query,
}
const options: Record<string, any> = {}
if (params.path) {
const trimmedPath = params.path.trim()
options.path = trimmedPath === '/' ? '' : trimmedPath
}
if (params.fileExtensions) {
const extensions = params.fileExtensions
.split(',')
.map((ext) => ext.trim())
.filter((ext) => ext.length > 0)
if (extensions.length > 0) {
options.file_extensions = extensions
}
}
if (params.maxResults) {
options.max_results = params.maxResults
}
if (Object.keys(options).length > 0) {
body.options = options
}
return body
},
},
transformResponse: async (response) => {
const data = await response.json()
if (!response.ok) {
return {
success: false,
error: data.error_summary || data.error?.message || 'Failed to search files',
output: {},
}
}
return {
success: true,
output: {
matches: data.matches || [],
hasMore: data.has_more || false,
cursor: data.cursor,
},
}
},
outputs: {
matches: {
type: 'array',
description: 'Search results',
items: {
type: 'object',
properties: {
match_type: {
type: 'object',
description: 'Type of match: filename, content, or both',
},
metadata: {
type: 'object',
description: 'File or folder metadata',
},
},
},
},
hasMore: {
type: 'boolean',
description: 'Whether there are more results',
},
cursor: {
type: 'string',
description: 'Cursor for pagination',
},
},
}
+307
View File
@@ -0,0 +1,307 @@
import type { UserFileLike } from '@/lib/core/utils/user-file'
import type { ToolFileData, ToolResponse } from '@/tools/types'
// ===== Core Types =====
interface DropboxFileMetadata {
'.tag': 'file'
id: string
name: string
path_display?: string
path_lower?: string
size: number
client_modified: string
server_modified: string
rev: string
content_hash?: string
is_downloadable?: boolean
}
interface DropboxFolderMetadata {
'.tag': 'folder'
id: string
name: string
path_display?: string
path_lower?: string
}
interface DropboxDeletedMetadata {
'.tag': 'deleted'
name: string
path_display?: string
path_lower?: string
}
export type DropboxMetadata = DropboxFileMetadata | DropboxFolderMetadata | DropboxDeletedMetadata
interface DropboxSharedLinkMetadata {
url: string
name: string
path_lower: string
link_permissions: {
can_revoke: boolean
resolved_visibility: {
'.tag': 'public' | 'team_only' | 'password' | 'team_and_password' | 'shared_folder_only'
}
revoke_failure_reason?: {
'.tag': string
}
}
expires?: string
id?: string
}
interface DropboxSearchMatch {
match_type: {
'.tag': 'filename' | 'content' | 'both'
}
metadata: {
'.tag': 'metadata'
metadata: DropboxMetadata
}
}
// ===== Base Params =====
interface DropboxBaseParams {
accessToken?: string
}
// ===== Upload Params =====
export interface DropboxUploadParams extends DropboxBaseParams {
path: string
file?: UserFileLike
// Legacy field for backwards compatibility
fileContent?: string
fileName?: string
mode?: 'add' | 'overwrite'
autorename?: boolean
mute?: boolean
}
export interface DropboxUploadResponse extends ToolResponse {
output: {
file?: DropboxFileMetadata
}
}
// ===== Download Params =====
export interface DropboxDownloadParams extends DropboxBaseParams {
path: string
}
export interface DropboxDownloadResponse extends ToolResponse {
output: {
file?: ToolFileData
content?: string // Base64 encoded file content
metadata?: DropboxFileMetadata
temporaryLink?: string
}
}
// ===== List Folder Params =====
export interface DropboxListFolderParams extends DropboxBaseParams {
path: string
recursive?: boolean
includeDeleted?: boolean
includeMediaInfo?: boolean
limit?: number
}
export interface DropboxListFolderResponse extends ToolResponse {
output: {
entries?: DropboxMetadata[]
cursor?: string
hasMore?: boolean
}
}
// ===== Create Folder Params =====
export interface DropboxCreateFolderParams extends DropboxBaseParams {
path: string
autorename?: boolean
}
export interface DropboxCreateFolderResponse extends ToolResponse {
output: {
folder?: DropboxFolderMetadata
}
}
// ===== Delete Params =====
export interface DropboxDeleteParams extends DropboxBaseParams {
path: string
}
export interface DropboxDeleteResponse extends ToolResponse {
output: {
metadata?: DropboxMetadata
deleted?: boolean
}
}
// ===== Copy Params =====
export interface DropboxCopyParams extends DropboxBaseParams {
fromPath: string
toPath: string
autorename?: boolean
}
export interface DropboxCopyResponse extends ToolResponse {
output: {
metadata?: DropboxMetadata
}
}
// ===== Move Params =====
export interface DropboxMoveParams extends DropboxBaseParams {
fromPath: string
toPath: string
autorename?: boolean
}
export interface DropboxMoveResponse extends ToolResponse {
output: {
metadata?: DropboxMetadata
}
}
// ===== Get Metadata Params =====
export interface DropboxGetMetadataParams extends DropboxBaseParams {
path: string
includeMediaInfo?: boolean
includeDeleted?: boolean
}
export interface DropboxGetMetadataResponse extends ToolResponse {
output: {
metadata?: DropboxMetadata
}
}
// ===== Create Shared Link Params =====
export interface DropboxCreateSharedLinkParams extends DropboxBaseParams {
path: string
requestedVisibility?: 'public' | 'team_only' | 'password'
linkPassword?: string
expires?: string
}
export interface DropboxCreateSharedLinkResponse extends ToolResponse {
output: {
sharedLink?: DropboxSharedLinkMetadata
}
}
// ===== Search Params =====
export interface DropboxSearchParams extends DropboxBaseParams {
query: string
path?: string
fileExtensions?: string
maxResults?: number
}
export interface DropboxSearchResponse extends ToolResponse {
output: {
matches?: DropboxSearchMatch[]
hasMore?: boolean
cursor?: string
}
}
// ===== Get Temporary Link Params =====
interface DropboxGetTemporaryLinkParams extends DropboxBaseParams {
path: string
}
interface DropboxGetTemporaryLinkResponse extends ToolResponse {
output: {
metadata?: DropboxFileMetadata
link?: string
}
}
// ===== List Shared Links Params =====
export interface DropboxListSharedLinksParams extends DropboxBaseParams {
path?: string
directOnly?: boolean
cursor?: string
}
export interface DropboxListSharedLinksResponse extends ToolResponse {
output: {
links?: DropboxSharedLinkMetadata[]
hasMore?: boolean
cursor?: string
}
}
// ===== List Revisions Params =====
interface DropboxFileRevision {
'.tag': 'file'
id: string
name: string
path_display?: string
path_lower?: string
size: number
rev: string
server_modified: string
}
export interface DropboxListRevisionsParams extends DropboxBaseParams {
path: string
limit?: number
beforeRev?: string
}
export interface DropboxListRevisionsResponse extends ToolResponse {
output: {
entries?: DropboxFileRevision[]
isDeleted?: boolean
hasMore?: boolean
}
}
// ===== Restore Params =====
export interface DropboxRestoreParams extends DropboxBaseParams {
path: string
rev: string
}
export interface DropboxRestoreResponse extends ToolResponse {
output: {
metadata?: DropboxFileMetadata
}
}
// ===== Combined Response Type =====
export type DropboxResponse =
| DropboxUploadResponse
| DropboxDownloadResponse
| DropboxListFolderResponse
| DropboxCreateFolderResponse
| DropboxDeleteResponse
| DropboxCopyResponse
| DropboxMoveResponse
| DropboxGetMetadataResponse
| DropboxCreateSharedLinkResponse
| DropboxSearchResponse
| DropboxGetTemporaryLinkResponse
| DropboxListSharedLinksResponse
| DropboxListRevisionsResponse
| DropboxRestoreResponse
+118
View File
@@ -0,0 +1,118 @@
import type { DropboxUploadParams, DropboxUploadResponse } from '@/tools/dropbox/types'
import type { ToolConfig } from '@/tools/types'
export const dropboxUploadTool: ToolConfig<DropboxUploadParams, DropboxUploadResponse> = {
id: 'dropbox_upload',
name: 'Dropbox Upload File',
description: 'Upload a file to Dropbox',
version: '1.0.0',
oauth: {
required: true,
provider: 'dropbox',
},
params: {
path: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The path in Dropbox where the file should be saved (e.g., /folder/document.pdf)',
},
file: {
type: 'file',
required: false,
visibility: 'user-or-llm',
description: 'The file to upload (UserFile object)',
},
// Legacy field for backwards compatibility - hidden from UI
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 (used if path is a folder)',
},
mode: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Write mode: add (default) or overwrite',
},
autorename: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'If true, rename the file if there is a conflict',
},
mute: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: "If true, don't notify the user about this upload",
},
},
request: {
url: '/api/tools/dropbox/upload',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
path: params.path.trim(),
file: params.file,
fileContent: params.fileContent,
fileName: params.fileName,
mode: params.mode,
autorename: params.autorename,
mute: params.mute,
}),
},
transformResponse: async (response): Promise<DropboxUploadResponse> => {
const data = await response.json()
if (!data.success) {
return {
success: false,
error: data.error || 'Failed to upload file',
output: {},
}
}
return {
success: true,
output: data.output,
}
},
outputs: {
file: {
type: 'object',
description: 'The uploaded file metadata',
properties: {
id: { type: 'string', description: 'Unique identifier for the file' },
name: { type: 'string', description: 'Name of the file' },
path_display: { type: 'string', description: 'Display path of the file', optional: true },
path_lower: { type: 'string', description: 'Lowercase path of the file', optional: true },
size: { type: 'number', description: 'Size of the file in bytes' },
client_modified: { type: 'string', description: 'Client modification time' },
server_modified: { type: 'string', description: 'Server modification time' },
rev: { type: 'string', description: 'Revision identifier' },
content_hash: {
type: 'string',
description: 'Content hash for the file',
optional: true,
},
},
},
},
}