MCPcopy Index your code
hub / github.com/simstudioai/sim / executeVfsRead

Function executeVfsRead

apps/sim/lib/copilot/tools/handlers/vfs.ts:201–360  ·  view source on GitHub ↗
(
  params: Record<string, unknown>,
  context: ExecutionContext
)

Source from the content-addressed store, hash-verified

199}
200
201export async function executeVfsRead(
202 params: Record<string, unknown>,
203 context: ExecutionContext
204): Promise<ToolCallResult> {
205 const path = params.path as string | undefined
206 if (!path) {
207 return { success: false, error: "Missing required parameter 'path'" }
208 }
209
210 const workspaceId = context.workspaceId
211 if (!workspaceId) {
212 return { success: false, error: 'No workspace context available' }
213 }
214
215 try {
216 const parseOptionalNumber = (value: unknown): number | undefined => {
217 if (typeof value === 'number' && Number.isFinite(value)) return value
218 if (typeof value === 'string' && value.trim() !== '') {
219 const parsed = Number.parseInt(value, 10)
220 return Number.isFinite(parsed) ? parsed : undefined
221 }
222 return undefined
223 }
224 const offset = parseOptionalNumber(params.offset)
225 const limit = parseOptionalNumber(params.limit)
226 const applyWindow = <T extends { content: string; totalLines: number }>(result: T): T => {
227 if (offset === undefined && limit === undefined) return result
228 const lines = result.content.split('\n')
229 const start = Math.max(0, Math.min(result.totalLines, offset ?? 0))
230 const endRaw = limit !== undefined ? start + Math.max(0, limit) : result.totalLines
231 const end = Math.max(start, Math.min(result.totalLines, endRaw))
232 return {
233 ...result,
234 content: lines.slice(start, end).join('\n'),
235 }
236 }
237
238 // Handle chat-scoped uploads via the uploads/ virtual prefix.
239 // Uploads are flat and have no metadata/content split like files/ — the upload
240 // IS the first path segment after uploads/. Any trailing segment (e.g. a
241 // /content suffix added out of habit) is ignored so the read resolves either way.
242 if (path.startsWith('uploads/')) {
243 if (!context.chatId) {
244 return { success: false, error: 'No chat context available for uploads/' }
245 }
246 const filename = path.slice('uploads/'.length).split('/')[0]
247 const uploadResult = await readChatUpload(filename, context.chatId)
248 if (uploadResult) {
249 const isAttachment = hasModelAttachment(uploadResult)
250 if (
251 !isAttachment &&
252 (isOversizedReadPlaceholder(uploadResult.content) ||
253 serializedResultSize(uploadResult) > TOOL_RESULT_MAX_INLINE_CHARS)
254 ) {
255 logger.warn('Upload read result too large', {
256 path,
257 hasAttachment: isAttachment,
258 contentLength: uploadResult.content.length,

Callers 1

vfs.test.tsFile · 0.90

Calls 15

readChatUploadFunction · 0.90
getOrMaterializeVFSFunction · 0.90
toErrorFunction · 0.90
getErrorMessageFunction · 0.90
parseOptionalNumberFunction · 0.85
hasModelAttachmentFunction · 0.85
serializedResultSizeFunction · 0.85
applyWindowFunction · 0.85
debugMethod · 0.80
testMethod · 0.80
readFileContentMethod · 0.80

Tested by

no test coverage detected