FileViewerModal component in Suna, an open source generalist AI agent.

In this article, we review a component named FileViewerModal in Suna codebase. Suna is an Open Source Generalist AI Agent. Where is FileViewerModal component used? I explored Suna by creating an account and created few chats. As part of the conversation response, there are tags and list of files responded as shown in the below image. When you click on any file here, the below modal appears. This is rendered by the FileViewerModal component. If you look at this page’s url, it looks something like this — https://www.suna.so/agents/{id} Suna does not use any monorepo setup, it contains backend and frontend folders. Frontend is built using Next.js app router, so we can expect a folder named “agents” and a dynamic route. As you can see, the [threadId] folder is used for dynamic routing in app router based Next.js project. At line 1548 in [threadId]/page.tsx, you will find the below code: {sandboxId && ( )} FileViewerModal component This component is defined in components/thread/file-viewer-modal.tsx. At the time of writing this article, this FileViewerModal component has 905 LOC. Below code is response to fetch the file that should be loaded in the viewer. // Load files when modal opens or path changes - Refined useEffect(() => { if (!open || !sandboxId) { return; // Don't load if modal is closed or no sandbox ID } const loadFiles = async () => { setIsLoadingFiles(true); console.log(`[FILE VIEWER] useEffect[currentPath]: Triggered. Loading files for path: ${currentPath}`); try { const filesData = await listSandboxFiles(sandboxId, currentPath); console.log(`[FILE VIEWER] useEffect[currentPath]: API returned ${filesData.length} files.`); setFiles(filesData); } catch (error) { console.error("Failed to load files:", error); toast.error("Failed to load files"); setFiles([]); } finally { setIsLoadingFiles(false); } }; loadFiles(); // Dependency: Only re-run when open, sandboxId, or currentPath changes }, [open, sandboxId, currentPath]); Dialog component used is a Shadcn/ui component, located at components/ui/dialog.tsx. File is rendered using another component called FileRenderer. About me: Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos. Want me to review your codebase architecture? book a meeting — https://thinkthroo.com/consultation/codebase-architecture-review Business enquiries — ramu@thinkthroo.com My Github —  https://github.com/ramu-narasinga My website —  https://ramunarasinga.com My YouTube channel —  https://www.youtube.com/@ramu-narasinga Learning platform —  https://thinkthroo.com Codebase Architecture —  https://app.thinkthroo.com/architecture Best practices —  https://app.thinkthroo.com/best-practices Production-grade projects —  https://app.thinkthroo.com/production-grade-projects References: https://github.com/kortix-ai/suna/blob/main/frontend/src/app/(dashboard)/agents/%5BthreadId%5D/page.tsx#L1610 https://github.com/kortix-ai/suna/blob/main/frontend/src/components/thread/file-viewer-modal.tsx#L39

Apr 28, 2025 - 05:17
 0
FileViewerModal component in Suna, an open source generalist AI agent.

In this article, we review a component named FileViewerModal in Suna codebase. Suna is an Open Source Generalist AI Agent.

Where is FileViewerModal component used?

I explored Suna by creating an account and created few chats. As part of the conversation response, there are tags and list of files responded as shown in the below image.

When you click on any file here, the below modal appears.

This is rendered by the FileViewerModal component. If you look at this page’s url, it looks something like this — https://www.suna.so/agents/{id}

Suna does not use any monorepo setup, it contains backend and frontend folders. Frontend is built using Next.js app router, so we can expect a folder named “agents” and a dynamic route.

As you can see, the [threadId] folder is used for dynamic routing in app router based Next.js project. At line 1548 in [threadId]/page.tsx, you will find the below code:

{sandboxId && (
  <FileViewerModal
    open={fileViewerOpen}
    onOpenChange={setFileViewerOpen}
    sandboxId={sandboxId}
    initialFilePath={fileToView}
    project={project || undefined}
  />
)}

FileViewerModal component

This component is defined in components/thread/file-viewer-modal.tsx. At the time of writing this article, this FileViewerModal component has 905 LOC.

Below code is response to fetch the file that should be loaded in the viewer.

// Load files when modal opens or path changes - Refined
  useEffect(() => {
    if (!open || !sandboxId) {
      return; // Don't load if modal is closed or no sandbox ID
    }

    const loadFiles = async () => {
      setIsLoadingFiles(true);
      console.log(`[FILE VIEWER] useEffect[currentPath]: Triggered. Loading files for path: ${currentPath}`);
      try {
        const filesData = await listSandboxFiles(sandboxId, currentPath);
        console.log(`[FILE VIEWER] useEffect[currentPath]: API returned ${filesData.length} files.`);
        setFiles(filesData);
      } catch (error) {
        console.error("Failed to load files:", error);
        toast.error("Failed to load files");
        setFiles([]);
      } finally {
        setIsLoadingFiles(false);
      }
    };

    loadFiles();
    // Dependency: Only re-run when open, sandboxId, or currentPath changes
  }, [open, sandboxId, currentPath]);

Dialog component used is a Shadcn/ui component, located at components/ui/dialog.tsx.

File is rendered using another component called FileRenderer.

<div className="h-full w-full relative">
  <FileRenderer
    key={selectedFilePath}
    content={textContentForRenderer}
    binaryUrl={blobUrlForRenderer}
    fileName={selectedFilePath}
    className="h-full w-full"
    project={projectWithSandbox}
    markdownRef={isMarkdownFile(selectedFilePath) ? markdownRef : undefined}
  />
</div>

About me:

Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.

Want me to review your codebase architecture? book a meeting —https://thinkthroo.com/consultation/codebase-architecture-review

Business enquiries — ramu@thinkthroo.com

My Github —  https://github.com/ramu-narasinga

My website —  https://ramunarasinga.com

My YouTube channel —  https://www.youtube.com/@ramu-narasinga

Learning platform —  https://thinkthroo.com

Codebase Architecture —  https://app.thinkthroo.com/architecture

Best practices —  https://app.thinkthroo.com/best-practices

Production-grade projects —  https://app.thinkthroo.com/production-grade-projects

References:

  1. https://github.com/kortix-ai/suna/blob/main/frontend/src/app/(dashboard)/agents/%5BthreadId%5D/page.tsx#L1610

  2. https://github.com/kortix-ai/suna/blob/main/frontend/src/components/thread/file-viewer-modal.tsx#L39