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

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,248 @@
import { createLogger } from '@sim/logger'
import { getBaseUrl } from '@/lib/core/utils/urls'
import {
deleteFile,
downloadFile,
generatePresignedDownloadUrl,
generatePresignedUploadUrl,
uploadFile,
} from '@/lib/uploads/core/storage-service'
import type { PresignedUrlResponse } from '@/lib/uploads/shared/types'
import { isImageFileType } from '@/lib/uploads/utils/file-utils'
const logger = createLogger('CopilotFileManager')
const SUPPORTED_FILE_TYPES = [
// Images
'image/jpeg',
'image/jpg',
'image/png',
'image/gif',
'image/webp',
'image/svg+xml',
// Documents
'application/pdf',
'text/plain',
'text/csv',
'text/markdown',
'text/html',
'application/json',
'application/xml',
'text/xml',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'text/x-pptxgenjs',
'text/x-docxjs',
'text/x-python-pdf',
'text/x-python-xlsx',
]
/**
* Check if a MIME type is supported for copilot attachments
*/
export function isSupportedFileType(mimeType: string): boolean {
return SUPPORTED_FILE_TYPES.includes(mimeType.toLowerCase())
}
interface CopilotFileAttachment {
key: string
filename: string
media_type: string
}
export interface GenerateCopilotUploadUrlOptions {
fileName: string
contentType: string
fileSize: number
userId: string
expirationSeconds?: number
}
export interface CopilotStoredFile {
id: string
key: string
context: 'copilot'
name: string
url: string
size: number
type: string
mimeType: string
}
/**
* Generate a presigned URL for copilot file upload
*
* Images and document files are allowed for copilot uploads.
* Requires authenticated user session.
*
* @param options Upload URL generation options
* @returns Presigned URL response with upload URL and file key
* @throws Error if file type is unsupported or user is not authenticated
*/
export async function generateCopilotUploadUrl(
options: GenerateCopilotUploadUrlOptions
): Promise<PresignedUrlResponse> {
const { fileName, contentType, fileSize, userId, expirationSeconds = 3600 } = options
if (!userId?.trim()) {
throw new Error('Authenticated user session is required for copilot uploads')
}
if (!isSupportedFileType(contentType) && !isImageFileType(contentType)) {
throw new Error(
'Unsupported file type. Allowed: images (JPEG, PNG, GIF, WebP), PDF, and text files (TXT, CSV, MD, HTML, JSON, XML).'
)
}
const presignedUrlResponse = await generatePresignedUploadUrl({
fileName,
contentType,
fileSize,
context: 'copilot',
userId,
expirationSeconds,
})
logger.info(`Generated copilot upload URL for: ${fileName}`, {
key: presignedUrlResponse.key,
userId,
})
return presignedUrlResponse
}
export async function uploadCopilotFile(options: {
buffer: Buffer
fileName: string
contentType: string
userId: string
}): Promise<CopilotStoredFile> {
const fileInfo = await uploadFile({
file: options.buffer,
fileName: options.fileName,
contentType: options.contentType,
context: 'copilot',
metadata: {
userId: options.userId,
originalName: options.fileName,
uploadedAt: new Date().toISOString(),
purpose: 'copilot-tool-output',
},
})
const url = `${getBaseUrl()}${fileInfo.path}`
logger.info(`Stored copilot tool output: ${options.fileName}`, {
key: fileInfo.key,
size: fileInfo.size,
userId: options.userId,
})
return {
id: fileInfo.key,
key: fileInfo.key,
context: 'copilot',
name: fileInfo.name,
url,
size: fileInfo.size,
type: fileInfo.type,
mimeType: fileInfo.type,
}
}
/**
* Download a copilot file from storage
*
* Uses the unified storage service with explicit copilot context.
* Handles S3, Azure Blob, and local storage automatically.
*
* @param key File storage key
* @returns File buffer
* @throws Error if file not found or download fails
*/
export async function downloadCopilotFile(key: string): Promise<Buffer> {
try {
const fileBuffer = await downloadFile({
key,
context: 'copilot',
})
logger.info(`Successfully downloaded copilot file: ${key}`, {
size: fileBuffer.length,
})
return fileBuffer
} catch (error) {
logger.error(`Failed to download copilot file: ${key}`, error)
throw error
}
}
/**
* Process copilot file attachments for chat messages
*
* Downloads files from storage and validates they are supported types.
* Skips unsupported files with a warning.
*
* @param attachments Array of file attachments
* @param requestId Request identifier for logging
* @returns Array of buffers for successfully downloaded files
*/
export async function processCopilotAttachments(
attachments: CopilotFileAttachment[],
requestId: string
): Promise<Array<{ buffer: Buffer; attachment: CopilotFileAttachment }>> {
const results: Array<{ buffer: Buffer; attachment: CopilotFileAttachment }> = []
for (const attachment of attachments) {
try {
if (!isSupportedFileType(attachment.media_type)) {
logger.warn(`[${requestId}] Unsupported file type: ${attachment.media_type}`)
continue
}
const buffer = await downloadCopilotFile(attachment.key)
results.push({ buffer, attachment })
} catch (error) {
logger.error(`[${requestId}] Failed to process file ${attachment.filename}:`, error)
}
}
logger.info(`Successfully processed ${results.length}/${attachments.length} attachments`, {
requestId,
})
return results
}
/**
* Generate a presigned download URL for a copilot file
*
* @param key File storage key
* @param expirationSeconds Time in seconds until URL expires (default: 1 hour)
* @returns Presigned download URL
*/
export async function generateCopilotDownloadUrl(
key: string,
expirationSeconds = 3600
): Promise<string> {
const downloadUrl = await generatePresignedDownloadUrl(key, 'copilot', expirationSeconds)
logger.info(`Generated copilot download URL for: ${key}`)
return downloadUrl
}
/**
* Delete a copilot file from storage
*
* @param key File storage key
*/
export async function deleteCopilotFile(key: string): Promise<void> {
await deleteFile({
key,
context: 'copilot',
})
logger.info(`Successfully deleted copilot file: ${key}`)
}
@@ -0,0 +1,6 @@
export type { CopilotStoredFile } from './copilot-file-manager'
export {
downloadCopilotFile,
generateCopilotUploadUrl,
uploadCopilotFile,
} from './copilot-file-manager'