feat(skill): add preprocessing for markdown files before upload

Introduce prepareSkillUploadFile utility that wraps markdown file content
in a JSON payload format before uploading. This ensures consistent handling
of skill files across file upload, folder upload, and drag-and-drop operations.
This commit is contained in:
yyh
2026-01-28 20:17:21 +08:00
parent fb78a4450d
commit 76c4d7f62c
3 changed files with 29 additions and 6 deletions

View File

@ -9,6 +9,7 @@ import {
useCreateAppAssetFolder,
useUploadFileWithPresignedUrl,
} from '@/service/use-app-asset'
import { prepareSkillUploadFile } from '../utils/skill-upload-utils'
type UseCreateOperationsOptions = {
parentId: string | null
@ -59,8 +60,9 @@ export function useCreateOperations({
storeApi.getState().setUploadProgress({ uploaded: 0, total, failed: 0 })
try {
const uploadFiles = await Promise.all(files.map(file => prepareSkillUploadFile(file)))
await Promise.all(
files.map(async (file) => {
uploadFiles.map(async (file) => {
try {
await uploadFile.mutateAsync({ appId, file, parentId })
uploaded++
@ -98,10 +100,14 @@ export function useCreateOperations({
const fileMap = new Map<string, File>()
const tree: BatchUploadNodeInput[] = []
const folderMap = new Map<string, BatchUploadNodeInput>()
for (const file of files) {
const uploadFiles = await Promise.all(files.map(async (file) => {
const relativePath = getRelativePath(file)
fileMap.set(relativePath, file)
const uploadFile = await prepareSkillUploadFile(file)
return { relativePath, uploadFile }
}))
for (const { relativePath, uploadFile } of uploadFiles) {
fileMap.set(relativePath, uploadFile)
const parts = relativePath.split('/')
let currentLevel = tree
@ -116,7 +122,7 @@ export function useCreateOperations({
currentLevel.push({
name: part,
node_type: 'file',
size: file.size,
size: uploadFile.size,
})
}
else {

View File

@ -10,6 +10,7 @@ import Toast from '@/app/components/base/toast'
import { useWorkflowStore } from '@/app/components/workflow/store'
import { useUploadFileWithPresignedUrl } from '@/service/use-app-asset'
import { ROOT_ID } from '../constants'
import { prepareSkillUploadFile } from '../utils/skill-upload-utils'
type FileDropTarget = {
folderId: string | null
@ -78,8 +79,9 @@ export function useFileDrop() {
return
try {
const uploadFiles = await Promise.all(files.map(file => prepareSkillUploadFile(file)))
await Promise.all(
files.map(file =>
uploadFiles.map(file =>
uploadFile.mutateAsync({
appId,
file,

View File

@ -0,0 +1,15 @@
import { getFileExtension, isMarkdownFile } from './file-utils'
const buildSkillUploadPayload = (content: string) => {
return JSON.stringify({ content, metadata: {} })
}
export async function prepareSkillUploadFile(file: File): Promise<File> {
const extension = getFileExtension(file.name)
if (!isMarkdownFile(extension))
return file
const content = await file.text()
const payload = buildSkillUploadPayload(content)
return new File([payload], file.name, { type: file.type || 'text/plain' })
}