Skip to content

Commit 94c2d7a

Browse files
committed
Merge branch 'dev' of github.com:simstudioai/sim into dev
2 parents 6de9774 + 63a6215 commit 94c2d7a

4 files changed

Lines changed: 68 additions & 90 deletions

File tree

apps/sim/app/workspace/[workspaceId]/files/[fileId]/view/file-viewer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function FileViewer() {
1717
return null
1818
}
1919

20-
const serveUrl = `/api/files/serve/${encodeURIComponent(file.key)}?context=workspace`
20+
const serveUrl = `/api/files/serve/${encodeURIComponent(file.key)}?context=workspace&t=${file.size}`
2121

2222
return (
2323
<div className='fixed inset-0 z-50 bg-[var(--bg)]'>

apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/file-viewer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ const ZOOM_BUTTON_FACTOR = 1.2
502502
const clampZoom = (z: number) => Math.min(Math.max(z, ZOOM_MIN), ZOOM_MAX)
503503

504504
const ImagePreview = memo(function ImagePreview({ file }: { file: WorkspaceFileRecord }) {
505-
const serveUrl = `/api/files/serve/${encodeURIComponent(file.key)}?context=workspace`
505+
const serveUrl = `/api/files/serve/${encodeURIComponent(file.key)}?context=workspace&t=${file.size}`
506506
const [zoom, setZoom] = useState(1)
507507
const [offset, setOffset] = useState({ x: 0, y: 0 })
508508
const isDragging = useRef(false)

apps/sim/lib/copilot/tools/server/files/workspace-file.ts

Lines changed: 65 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
deleteWorkspaceFile,
1616
downloadWorkspaceFile as downloadWsFile,
1717
getWorkspaceFile,
18+
getWorkspaceFileByName,
1819
renameWorkspaceFile,
1920
updateWorkspaceFileContent,
2021
uploadWorkspaceFile,
@@ -99,20 +100,76 @@ export const workspaceFileServerTool: BaseServerTool<WorkspaceFileArgs, Workspac
99100
const isPptx = lowerName.endsWith('.pptx')
100101
const isDocx = lowerName.endsWith('.docx')
101102
const isPdf = lowerName.endsWith('.pdf')
102-
let contentType: string
103+
const isDoc = isPptx || isDocx || isPdf
104+
const sourceMime = isPptx
105+
? PPTX_SOURCE_MIME
106+
: isDocx
107+
? DOCX_SOURCE_MIME
108+
: isPdf
109+
? PDF_SOURCE_MIME
110+
: undefined
103111

104-
if (isPptx || isDocx || isPdf) {
112+
const existingFile = await getWorkspaceFileByName(workspaceId, fileName)
113+
114+
if (existingFile) {
115+
const currentBuffer = await downloadWsFile(existingFile)
116+
const combined = `${currentBuffer.toString('utf-8')}\n${content}`
117+
118+
if (isDoc) {
119+
const formatName = isPptx ? 'PPTX' : isDocx ? 'DOCX' : 'PDF'
120+
const generator = isPptx
121+
? generatePptxFromCode
122+
: isDocx
123+
? generateDocxFromCode
124+
: generatePdfFromCode
125+
try {
126+
await generator(combined, workspaceId)
127+
} catch (err) {
128+
const msg = err instanceof Error ? err.message : String(err)
129+
return {
130+
success: false,
131+
message: `${formatName} generation failed after append: ${msg}. Fix the content and retry.`,
132+
}
133+
}
134+
}
135+
136+
const combinedBuffer = Buffer.from(combined, 'utf-8')
137+
assertServerToolNotAborted(context)
138+
await updateWorkspaceFileContent(
139+
workspaceId,
140+
existingFile.id,
141+
context.userId,
142+
combinedBuffer,
143+
sourceMime
144+
)
145+
146+
logger.info('Workspace file appended via write', {
147+
fileId: existingFile.id,
148+
name: fileName,
149+
appendedSize: content.length,
150+
totalSize: combinedBuffer.length,
151+
userId: context.userId,
152+
})
153+
154+
return {
155+
success: true,
156+
message: `Content appended to "${fileName}" (${content.length} bytes added, ${combinedBuffer.length} bytes total)`,
157+
data: {
158+
id: existingFile.id,
159+
name: fileName,
160+
size: combinedBuffer.length,
161+
},
162+
}
163+
}
164+
165+
let contentType: string
166+
if (isDoc) {
105167
const formatName = isPptx ? 'PPTX' : isDocx ? 'DOCX' : 'PDF'
106168
const generator = isPptx
107169
? generatePptxFromCode
108170
: isDocx
109171
? generateDocxFromCode
110172
: generatePdfFromCode
111-
const sourceMime = isPptx
112-
? PPTX_SOURCE_MIME
113-
: isDocx
114-
? DOCX_SOURCE_MIME
115-
: PDF_SOURCE_MIME
116173
try {
117174
await generator(content, workspaceId)
118175
} catch (err) {
@@ -123,7 +180,7 @@ export const workspaceFileServerTool: BaseServerTool<WorkspaceFileArgs, Workspac
123180
message: `${formatName} generation failed: ${msg}. Fix the code and retry.`,
124181
}
125182
}
126-
contentType = sourceMime
183+
contentType = sourceMime!
127184
} else {
128185
contentType = inferContentType(fileName, explicitType)
129186
}
@@ -301,85 +358,6 @@ export const workspaceFileServerTool: BaseServerTool<WorkspaceFileArgs, Workspac
301358
}
302359
}
303360

304-
case 'append': {
305-
const fileId = (args as Record<string, unknown>).fileId as string | undefined
306-
const content = (args as Record<string, unknown>).content as string | undefined
307-
308-
if (!fileId) {
309-
return { success: false, message: 'fileId is required for append operation' }
310-
}
311-
if (!content) {
312-
return { success: false, message: 'content is required for append operation' }
313-
}
314-
315-
const fileRecord = await getWorkspaceFile(workspaceId, fileId)
316-
if (!fileRecord) {
317-
return { success: false, message: `File with ID "${fileId}" not found` }
318-
}
319-
320-
const currentBuffer = await downloadWsFile(fileRecord)
321-
const combined = `${currentBuffer.toString('utf-8')}\n${content}`
322-
323-
const appendLowerName = fileRecord.name?.toLowerCase() ?? ''
324-
const isPptxAppend = appendLowerName.endsWith('.pptx')
325-
const isDocxAppend = appendLowerName.endsWith('.docx')
326-
const isPdfAppend = appendLowerName.endsWith('.pdf')
327-
const isDocAppend = isPptxAppend || isDocxAppend || isPdfAppend
328-
329-
if (isDocAppend) {
330-
const formatName = isPptxAppend ? 'PPTX' : isDocxAppend ? 'DOCX' : 'PDF'
331-
const generator = isPptxAppend
332-
? generatePptxFromCode
333-
: isDocxAppend
334-
? generateDocxFromCode
335-
: generatePdfFromCode
336-
try {
337-
await generator(combined, workspaceId)
338-
} catch (err) {
339-
const msg = err instanceof Error ? err.message : String(err)
340-
return {
341-
success: false,
342-
message: `Appended ${formatName} code failed to compile: ${msg}. Fix the content and retry.`,
343-
}
344-
}
345-
}
346-
347-
const appendSourceMime = isPptxAppend
348-
? PPTX_SOURCE_MIME
349-
: isDocxAppend
350-
? DOCX_SOURCE_MIME
351-
: isPdfAppend
352-
? PDF_SOURCE_MIME
353-
: undefined
354-
const appendBuffer = Buffer.from(combined, 'utf-8')
355-
assertServerToolNotAborted(context)
356-
await updateWorkspaceFileContent(
357-
workspaceId,
358-
fileId,
359-
context.userId,
360-
appendBuffer,
361-
appendSourceMime
362-
)
363-
364-
logger.info('Workspace file appended via copilot', {
365-
fileId,
366-
name: fileRecord.name,
367-
appendedSize: content.length,
368-
totalSize: appendBuffer.length,
369-
userId: context.userId,
370-
})
371-
372-
return {
373-
success: true,
374-
message: `Content appended to "${fileRecord.name}" (${content.length} bytes added, ${appendBuffer.length} bytes total)`,
375-
data: {
376-
id: fileId,
377-
name: fileRecord.name,
378-
size: appendBuffer.length,
379-
},
380-
}
381-
}
382-
383361
case 'patch': {
384362
const fileId = (args as Record<string, unknown>).fileId as string | undefined
385363
const edits = (args as Record<string, unknown>).edits as

apps/sim/lib/copilot/tools/shared/schemas.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ export type UserTableResult = z.infer<typeof UserTableResultSchema>
176176

177177
// workspace_file - shared schema used by server tool and Go catalog
178178
export const WorkspaceFileArgsSchema = z.object({
179-
operation: z.enum(['write', 'update', 'append', 'delete', 'rename', 'patch']),
179+
operation: z.enum(['write', 'update', 'delete', 'rename', 'patch']),
180180
args: z
181181
.object({
182182
fileId: z.string().optional(),

0 commit comments

Comments
 (0)