Skip to main content
ChatGPT stores your app’s files and hands your code a reference to each, never the bytes. useFiles produces a reference from a file the user supplies, by uploading a local file or picking one from ChatGPT’s library, and resolves any reference into a download URL the view or a tool can fetch.

Example

A shopper attaches a receipt, from their device or their ChatGPT library, and the view hands it to a tool that scans it.
import { useState } from "react";
import { useFiles } from "skybridge/web";
import { useCallTool } from "../helpers.js"; // generated, type-safe from server schema

function ReceiptAttach() {
  const { upload, getDownloadUrl, selectFiles } = useFiles();
  const { callTool, isPending } = useCallTool("scan-receipt");
  const [error, setError] = useState<string>();

  const attachFromDevice = async (file: File) => {
    try {
      const meta = await upload(file);
      const { downloadUrl } = await getDownloadUrl(meta);
      callTool({
        receipt: {
          file_id: meta.fileId,
          download_url: downloadUrl,
          file_name: meta.fileName,
          mime_type: meta.mimeType,
        },
      });
    } catch (e) {
      setError(String(e));
    }
  };

  const attachFromLibrary = async () => {
    try {
      const [picked] = await selectFiles();
      if (!picked) {
        return;
      }
      const { downloadUrl } = await getDownloadUrl(picked);
      callTool({
        receipt: {
          file_id: picked.fileId,
          download_url: downloadUrl,
          file_name: picked.fileName,
          mime_type: picked.mimeType,
        },
      });
    } catch (e) {
      setError(String(e));
    }
  };

  return (
    <div>
      <input
        type="file"
        disabled={isPending}
        onChange={(e) => {
          const file = e.target.files?.[0];
          if (file) {
            attachFromDevice(file);
          }
        }}
      />
      <button disabled={isPending} onClick={attachFromLibrary}>
        Pick from library
      </button>
      {error && <p>Could not attach receipt: {error}</p>}
    </div>
  );
}
Both paths resolve a download URL and build a FileRef by hand: the hook returns camelCase fields, while FileRef wants snake_case with a required download_url.

Returns

useFiles returns three functions.

upload

upload(file: File): Promise<FileMetadata>;
Sends a File to the host and resolves with its FileMetadata, a reference to the stored file (the host never gives the view the bytes, only this handle):
type FileMetadata = {
  fileId: string;
  fileName?: string;
  mimeType?: string;
};

getDownloadUrl

getDownloadUrl(file: FileMetadata): Promise<{ downloadUrl: string }>;
Resolves a download URL for a host-managed file: one returned by upload or selectFiles, or one delivered to the view through a tool’s output.

selectFiles

selectFiles(): Promise<FileMetadata[]>;
Opens ChatGPT’s file library picker and resolves with the FileMetadata of the files the user authorizes for the app. The array is empty when the user picks nothing.

Handle Files

Move files in and out of your app across hosts

FileRef

The schema that passes a file reference to a tool

useCallTool

Forward an uploaded file into a tool call