assistant-ui icon indicating copy to clipboard operation
assistant-ui copied to clipboard

Please add file upload functionality to message composer attachments

Open vincenzodomina opened this issue 7 months ago • 2 comments

Current Behavior: it is not straightforward how to allow other file uploads in the message composer attachments. Currently i can only add text and image content like so:

  const runtime = useExternalStoreRuntime<ThreadMessageLike>({
    ...
    adapters: {
      attachments: new CompositeAttachmentAdapter([
        new SimpleImageAttachmentAdapter(),
        new SimpleTextAttachmentAdapter(),
      ]),
    },
  });

Expected behavior: Be able to add a file attachment adapter

new SimpleFileAttachmentAdapter(),

So that at least for now until other files are supported, i can handle the file attachment incoming on the onNew method in the useExternalStoreRuntime

vincenzodomina avatar May 14 '25 13:05 vincenzodomina

As a workaround for now i added a custom made adapter, similar to the SimpleImageAttachmentAdapter, so that at least i can allow other file types in the file explorer:

import {
  PendingAttachment,
  CompleteAttachment,
  AttachmentAdapter,
} from "@assistant-ui/react";

export class SimpleFileAttachmentAdapter implements AttachmentAdapter {
  public accept = "*";

  public async add(state: { file: File }): Promise<PendingAttachment> {
    return {
      id: state.file.name,
      type: "file",
      name: state.file.name,
      contentType: state.file.type,
      file: state.file,
      status: { type: "requires-action", reason: "composer-send" },
    };
  }

  public async send(
    attachment: PendingAttachment,
  ): Promise<CompleteAttachment> {
    return {
      ...attachment,
      status: { type: "complete" },
      content: [
        {
          type: "file",
          data: await getFileDataURL(attachment.file),
          mimeType: attachment.file.type,
        },
      ],
    };
  }

  public async remove() {
    // noop
  }
}

const getFileDataURL = (file: File) =>
  new Promise<string>((resolve, reject) => {
    const reader = new FileReader();

    reader.onload = () => resolve(reader.result as string);
    reader.onerror = (error) => reject(error);

    reader.readAsDataURL(file);
  });

vincenzodomina avatar May 14 '25 13:05 vincenzodomina

@vincenzodomina can i try?

Surajsuthar avatar May 24 '25 17:05 Surajsuthar