Skip to content

Fix/prompt input hosted file uploads - #523

Open
AbbasFullstack wants to merge 5 commits into
vercel:mainfrom
AbbasFullstack:fix/prompt-input-hosted-file-uploads
Open

AbbasFullstack wants to merge 5 commits into
vercel:mainfrom
AbbasFullstack:fix/prompt-input-hosted-file-uploads

Conversation

@AbbasFullstack

Copy link
Copy Markdown

Summary

Adds optional hosted file upload support to "PromptInput".

Changes

  • Add an optional "onFileAdd" callback to upload files and return hosted URLs.
  • Add an optional "onFileRemove" callback for remote file cleanup.
  • Preserve the existing default attachment behavior when no upload callback is provided.
  • Prevent form submission while file uploads are pending.
  • Add tests for hosted URL submission and pending-upload submission blocking.

Testing

  • Added tests for hosted file uploads and pending upload states.
  • Tests have not been run yet.

Closes #89

@vercel

vercel Bot commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

@AbbasFullstack is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

@vercel vercel Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional findings

  1. packages/elements/src/prompt-input.tsx:1332-1337 — Passing disabled={false} leaves the submit button enabled during uploads because the trailing props spread overrides the upload lock, allowing click handlers to run while form submission silently returns.

    Fix on Vercel

Comment on lines +629 to +648
Promise.all(
capped.map(async (file) => ({
filename: file.name,
mediaType: file.type,
type: "file" as const,
url: onFileAdd ? await onFileAdd(file) : URL.createObjectURL(file),
}))
)
.then((uploaded) => {
if (usingProvider) {
controller?.attachments.addUploaded(uploaded);
} else {
setItems((prev) => [
...prev,
...uploaded.map((file) => ({ ...file, id: nanoid() })),
]);
}
})
.catch(() => {
// Keep existing attachments if an upload fails.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When one file in a multi-file hosted upload rejects, Promise.all discards every successful attachment in that batch without reporting an error or making those remote files available for removal.

Fix on Vercel

.catch(() => {
// Keep existing attachments if an upload fails.
})
.finally(() => setIsUploading(false));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When file selections overlap, either batch settling clears isUploading while the other is pending, allowing submission without the pending attachment and letting it appear in the next message.

Fix on Vercel

Comment on lines +615 to +619
const capacity =
typeof maxFiles === "number"
? Math.max(0, maxFiles - files.length)
: undefined;
const capped =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With maxFiles={1}, selecting a second file while the first upload is pending uploads and appends both files, exceeding the limit in both local and provider modes.

Fix on Vercel

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[PromptInput]: Support for hosted URL for files

1 participant