LibreChat/api/server/services
Anubhav Anand a2ad0aa0c8
🤐 feat: Allow Promptless Sends When Files Are Attached (#13717)
*  feat: Allow sending file attachments without a text message

When an agent asks the user to upload a document, the user could attach
the file but still had to type a placeholder message ("OK", "Here is
the file") before the send button enabled and the submit guard let the
message through.

Attachments now count as submittable content:

- New isSubmittableMessage(text, fileCount) util: non-whitespace text
  OR at least one attached file.
- ask() in useChatFunctions uses it instead of bailing on empty text,
  so an empty draft with attached files submits.
- SendButton receives the attached file count and enables accordingly.
- ChatForm only marks the text field as required when no files are
  attached, so react-hook-form validation no longer blocks handleSubmit.

Submitting an empty draft with no attachments is still rejected at all
three layers.

Fixes #13646

* Address review: support replayed file-only turns + drop empty vision text

- ask(): count replayed attachments (overrideFiles) in the submittable
  check and skip it entirely for regenerate, so a file-only message can
  be regenerated or saved-and-resubmitted instead of being rejected as
  empty.
- formatVisionMessage(): omit the text content part when the message text
  is empty. Anthropic rejects empty text content blocks with HTTP 400,
  and an empty block adds nothing for other providers; image-only sends
  now format cleanly. Added formatMessages tests for with-text and
  image-only (Anthropic + other) cases.

* Address review: keep attachment-only turns valid for providers, answer mode, and titles

- formatMessage: substitute minimal text when a user turn carries files but no
  inline content, so Anthropic does not reject an empty user message for RAG or
  code-environment attachments.
- assistants chatV1: send the same stand-in for attachment-only Threads
  messages, which reject an empty body. The persisted message keeps empty text.
- ChatForm: attachments no longer make an empty draft submittable in answer
  mode, where submitText consumes the click without answering or sending.
- agents request: seed title generation from attachment filenames when the turn
  has no text, so immediate-mode titles are not invented from an empty string.
- useChatFunctions.regenerate.spec: mock the utils barrel over the real module
  so new exports resolve.

* Cover the agents path for attachment-only turns

AgentClient formats its payload with the SDK's formatMessage, not the local
one, so the earlier guard missed the endpoint the feature actually targets: an
attachment-only turn still reached Anthropic as an empty user message. Apply
the same stand-in after the file-context and quote merges, so a turn that
already gained inline content is untouched.

* Carry filenames on freshly attached files

The fresh-file submission mapping copied only file_id, filepath, type, and
dimensions, so the attachment-only title fallback read an undefined filename
and produced nothing. Include filename, and cover it with a test that submits
an empty draft with one attachment.

* Address review: cover assistants v2, fresh agent attachments, editor, and title fallback

- agents client: the current turn has no files during buildMessages, so read
  the resolved attachments from message_file_map instead. The previous guard
  only ever fired for persisted historical turns.
- assistants chatV2: the default assistants endpoint routes here, so it needs
  the same stand-in body chatV1 got.
- assistants title: fall back to filenames, then the response, and keep the
  default title rather than saving an empty one.
- EditMessage: retained attachments make an empty edit submittable, matching
  the composer, so the overrideFiles replay path is reachable from the UI.

---------

Co-authored-by: Marco Beretta <81851188+berry-13@users.noreply.github.com>
2026-08-15 12:47:31 -04:00
..
__tests__ 🛰️ fix: Attach Request-Scoped MCP Servers (#14780) 2026-08-12 23:43:02 -04:00
Agents
Artifacts
Config 🧭 fix: Make MCP Catalog Redis Cluster-Safe (#14717) 2026-08-09 06:59:29 -04:00
Endpoints 🤐 feat: Allow Promptless Sends When Files Are Attached (#13717) 2026-08-15 12:47:31 -04:00
Files 🎙️ fix: Align Speech Engine Configuration With Runtime (#14736) 2026-08-12 13:22:28 -04:00
Runs
Skills
start
Threads
Tools 📡 fix: Refresh MCP Tools After List-Changed Notifications (#14686) 2026-08-08 13:50:21 -04:00
ActionService.js
ActionService.spec.js
AssistantService.js
AuthService.js
AuthService.spec.js
cleanup.js
createRunBody.js
GraphApiService.js
GraphApiService.spec.js
GraphTokenService.js
initializeMCPs.js 🔌 feat: Add Agent Plugins (Experimental) (#14704) 2026-08-09 08:10:22 -04:00
initializeMCPs.plugins.spec.js 🔌 feat: Add Agent Plugins (Experimental) (#14704) 2026-08-09 08:10:22 -04:00
initializeMCPs.spec.js 🔌 feat: Add Agent Plugins (Experimental) (#14704) 2026-08-09 08:10:22 -04:00
initializeOAuthReconnectManager.js
MCP.js 🧷 fix: Safely Recover Runtime MCP OAuth Rejections (#14684) 2026-08-10 10:38:34 -04:00
MCP.spec.js 🛰️ fix: Attach Request-Scoped MCP Servers (#14780) 2026-08-12 23:43:02 -04:00
MCPRequestContext.js
OboPolicyService.js
OboTokenService.js
OboTokenService.spec.js
PermissionService.js perf: Agent List and Model Selector at Scale (#14601) 2026-08-07 21:04:55 -04:00
PermissionService.spec.js perf: Agent List and Model Selector at Scale (#14601) 2026-08-07 21:04:55 -04:00
PluginService.js
systemGrant.spec.js
ToolService.js 🛰️ fix: Attach Request-Scoped MCP Servers (#14780) 2026-08-12 23:43:02 -04:00
twoFactorService.js