LibreChat/api/server/routes
Marco Beretta edd614bbff
🧰 feat: Redesign Agent Builder with Unified Tools Marketplace, Skills & Orchestration (#13952)
* feat: redesign the agent builder tools, skills, and advanced panels

Replace the stacked capability/MCP/skill/tool/action form sections with a unified tools marketplace, per-item configuration dialogs, and a consolidated Advanced panel.

- unified tools marketplace (catalog, sidebar, polymorphic cards/rows) covering built-in capabilities, plugins, MCP servers, and actions, each with a detail/config dialog
- dedicated Skills picker and a Tools section with selected-item summaries and empty states
- redesigned action editor and authentication dialog (method cards, segmented controls)
- rebuilt Advanced panel: orchestration hub (subagents, handoffs, chain), max steps, skills kill-switch, copyable agent id
- restyled version history (timeline, tool/capability counts, in-app restore confirmation)
- shared component updates (Radio, Input/Textarea, dropdown z-index, dialog primitives) and keyboard-only focus rings via useInputModality
- format-hint placeholders for tool credential fields
- sanitize numeric parameter inputs to prevent comma truncation

* feat: refine agent builder tools, actions, and MCP sections

* feat: restore Memory capability toggle in agent builder tools catalog

* feat: refine agent tools picker (skills, MCP connect/OAuth, web search)

- Skills picker: per-card visibility (public) and shared-author badges,
  category filtering, and an in-place Create skill flow that auto-attaches
  the new skill without leaving the builder
- MCP: inline Connect button in the first dialog plus a dedicated OAuth
  dialog (continue, copyable URL, QR code) shown only when OAuth is required
- Web search: auth-aware affordance, settings cog when user-provided and an
  info icon when system-defined
- Remove orphaned com_ui_unavailable/com_ui_initializing keys and the dead
  Tools/MCPToolItem component

* refactor: streamline MCP OAuth dialog

- Remove the Cancel button (the flow auto-closes on connect / times out)
- Show the URL in a read-only single-line scrollable input (cursor moves
  through it, not fully visible) with the shared CopyButton's smooth
  Copy/Check icon swap, matching the OAuth callback-URL field
- Put the primary Continue with OAuth action (icon trailing) and an
  icon-only QR toggle together in a row at the bottom, below the URL
- The QR reveals between the description and the URL with a smooth height
  animation (grid-rows 0fr to 1fr, matching MCPToolItem's reveal)

* feat: smoothly collapse MCP connect button once connected

* feat: cross-fade MCP tools between loading, list, and empty states

* feat: show MCP server icon in OAuth dialog title

* fix: vertically center OAuth dialog title against the MCP icon

* feat: smoothly animate auth field changes in the MCP server dialog

* feat: match Code Interpreter file upload to the File Search dropzone

Swap Code Interpreter's thin btn-neutral bar for the same dashed dropzone
(DropzoneContent + dropzoneClassName) File Search already uses, so the two
capabilities' upload UIs are consistent.

* feat: show a saving spinner and allow cancelling credential edits

Drive the tool credential Save button from the real mutation state so it
shows a spinner while the request is in flight, and add a Cancel button
when re-editing already-saved credentials so the edit can be dismissed.

* feat: make the skills create button a compact icon button

* fix: restore MCP attach semantics and confirmations in the tools marketplace

Connecting an MCP server from the item dialog now enables all of its tools
once the connection settles, deselect-all keeps the server attached via its
placeholder token instead of detaching it, adding a server writes the token
so a zero-tool attachment survives a save, and removing a server from the
tools list asks for confirmation again. Consume-only servers are excluded
from the catalog, matching the old select dialog.

Also share the catalog/selection pipeline between ToolsSection and the
marketplace through useAgentItems, hoist NEW_ACTION_ID next to ActionItem,
drop unused status/view union members and stale TranslationKeys casts,
document the phase-2 Favorites/Made-by-you views, fix the needs-setup dot
semantics and card focus suppression, remove the redundant close button in
CreateSkillDialog, move useInputModality into @librechat/client so external
consumers can mount it, and delete dead files and orphaned translation keys.

* fix: scope tooltip elevation to dialogs and restore dialog close button size

Tooltips go back to z-150 globally; inside a dialog they now borrow the
depth-aware popover z-index so they still clear nested dialogs (the Tool
Library item dialog) without outranking freshly opened modals everywhere
else. The default dialog close icon returns to its original size, and the
lc-field pointer-focus suppression ships with the package next to Input and
Textarea so external consumers get the whole mechanism from @librechat/client.

* feat: add favorites for marketplace tools, MCP servers, and skills

Reintroduce the favorite star from the old skill picker, generalized to
every marketplace item kind except per-agent actions. Cards in the Tool
Library and Skills dialogs get a hover-revealed star (always visible once
favorited), and the existing Favorites views in both dialogs now filter to
starred items.

Favorites persist in a dedicated ToolFavorite collection, one document per
(user, itemType, itemId) with a unique compound index, exposed through
atomic per-item PUT/DELETE endpoints under /api/user/settings/favorites/
tools. Per-item writes are idempotent and race-free across tabs/devices
(the unique index backstops concurrent toggles), reads are a single
index-backed query capped at 100 favorites per user, and the client keeps
React Query as the source of truth with optimistic updates. Handlers live
in @librechat/api with a thin route wrapper; methods follow the
data-schemas factory pattern with tenant isolation.

The favorites filter now matches on compound kind:id keys instead of bare
ids, closing a cross-kind collision where a tool and a skill sharing an id
would both match. The skill-favorites data-service stubs and the reserved
TUserFavorite.skillId field are replaced by the new tool-favorites service.

* feat: anchor the favorite star at the card's right edge

Swap the ToolCard action-bar order so the star sits rightmost with the
configure/info icon to its left. Every card can be favorited but only some
are configurable, so anchoring the star keeps it in a consistent position
across the grid.

* chore: remove translation keys orphaned by the tool library redesign

* fix: gate marketplace creation entries and resolve off-page selected skills

The Create New menu exposed MCP server creation to users without the
MCP_SERVERS create permission and action creation on deployments with the
actions capability disabled; both entries are now gated like their
pre-redesign counterparts, and the button hides when neither applies.

Selected skills missing from the first catalog page (limit 100) were
dropped from the Skills section entirely, leaving them impossible to
inspect or remove. useResolvedSkills restores the per-id lookup: off-page
skills are fetched individually and confirmed misses (deleted or no longer
shared) stay visible under an Unavailable skill placeholder so the stale
allowlist entry remains removable.

* fix: refetch favorites when toggled before the list loads, lint fixes

An optimistic favorite written over an unpopulated cache seeded the list
with only the toggled item, and cancelQueries killed the initial fetch
that would have corrected it, hiding existing favorites until reload. The
optimistic write now only applies over known data; otherwise onSettled
invalidates so the authoritative list is refetched.

Also unnest the version date-label ternary and drop an unused form watch
flagged by CI.

* fix: sync skills_enabled with selection edits and hydrate agent file entries

skills_enabled is the master opt-in for the skill allowlist, and an empty
allowlist with the flag on means the full accessible catalog. Selection
edits now sync the flag on empty/non-empty transitions via a shared
skillsEnabledTransition helper: picking the first skill enables it so the
choice takes effect on save, and removing the last one disables it so the
agent doesn't silently escalate to every skill. Mid-selection edits leave
the flag alone, preserving the Advanced kill switch's
disable-without-clearing behavior.

Agents loaded from the API carry only tool_resources.*.file_ids; the
client-only context/knowledge/code file entry arrays were read directly,
so existing attachments rendered as empty and could not be removed. A new
useAgentFileEntries hook restores the legacy derivation (agent files query
merged into the file map via processAgentOption) and now feeds AgentConfig,
the item dialog, and the selected-items pipeline.

* fix: hide plugin tools from the marketplace when the tools capability is off

buildCatalog gated built-ins, MCP, and skills on their capabilities and
permissions but pushed regular plugin tools unconditionally, so deployments
that removed the tools capability still offered attachable tool cards in
the marketplace. The loop now requires AgentCapabilities.tools, matching
the old Add Tools gate.

* fix: strip legacy MCP tokens on removal, guard action creation, model button spacing

MCP selection accepts every historical token format (server placeholder,
raw server name, mcp_-prefixed, and per-tool ids in prefix/suffix shapes)
but removal only filtered the new placeholder plus the server's current
tool ids, so a legacy token left the server permanently selected and its
tools still expanded after save. Selection and removal now share a
matchesMcpServer predicate.

Creating an action from the marketplace on an unsaved agent opened an
editor whose save was guaranteed to fail; it now surfaces the existing
save-the-agent-first error, matching the action-removal guard.

The model picker button keeps its tight px-1 with a provider icon but gets
px-3 in the empty Select-a-model state so the placeholder is not flush
against the border.

* fix: strip legacy prefix MCP tokens in useRemoveMCPTool

The hook only filtered the raw server name and suffix-delimiter tokens,
so confirming removal in the selected-tools section left persisted
prefix-format tokens (mcp_<server>, mcp_<server>_<tool>) in the form and
the row reappeared as selected. It now shares the matchesMcpServer
predicate with the selection logic so removal can never lag selection.

* fix: exact MCP token matching and keep errored skill lookups removable

The mcp_<server>_ prefix clause in matchesMcpServer was invented by the
redesign, not a persisted format (mcp_prefix is only ever used as the
exact mcp_<serverName> pluginKey), and it claimed longer server names
sharing a prefix: with servers github and github_extra, removing github
also stripped github_extra's tokens. The predicate now only matches exact
or delimiter-bounded shapes.

An off-page selected skill whose per-id lookup failed with a transient
error (retry disabled) vanished from the selected list until remount. Any
settled lookup failure now keeps the placeholder entry so the allowlist id
stays visible and removable; only in-flight lookups are briefly hidden.

* fix: route file-backed built-in removal to the file manager

Code Interpreter and File Search stay selected while they hold code_files
or knowledge_files, so removing them by flipping the capability flag left
the row visible and unremovable. Their removal now opens the config dialog
where the files are managed, mirroring the file-only context built-in;
with no files attached the flag still toggles off for a clean removal.

* fix: preserve negative values in numeric parameter inputs

sanitizeIntegerInput stripped every non-digit, so typing -1 in a numeric
parameter field became 1. That broke Google thinkingBudget, where -1 is
the dynamic/auto-thinking sentinel (range min is -1): users could no
longer select auto and risked sending a one-token budget. The sanitizer
now takes an opt-in allowNegative flag that keeps a single leading minus,
and DynamicInput passes it when the field's range permits negatives.
Thousands-separator cleanup is unchanged for all other fields.

* fix: keep in-progress negative numeric input and localize the actions heading

Typing a leading minus in a negative-capable numeric parameter (Google
thinkingBudget) sanitized to a lone '-', which was then coerced by
Number('-') to NaN, so the sign could not be typed before the digits. The
lone '-' is now stored as a string until a digit resolves it to a number,
matching how the empty-string case is already handled.

The agent builder actions panel heading hard-coded 'Add'/'Edit actions';
it now uses com_assistants_add_actions and a restored
com_assistants_edit_actions key so non-English locales translate it.

* chore: fix import order drift flagged by CI

* fix: treat pending web-search auth verification as needs_setup

While useVerifyAgentToolAuth is still loading, data is undefined so
web_search was not marked needs_setup, and the marketplace card takes the
direct-enable path only when status is not needs_setup. On a slow
connection a click before the response arrived enabled web_search without
collecting the required user-provided key. The auth map now flags
web_search needs_setup while the query is loading, routing the click to
the config dialog; once verification resolves, a system-defined deployment
or a satisfied key clears the flag for a direct toggle.

* test: update agent builder e2e selectors

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
2026-07-05 11:30:12 -04:00
..
__test-utils__ 🧹 feat: Eager HITL Checkpoint Cleanup (Expiry + Deletion) & Full-Wiring E2E (#14123) 2026-07-05 11:29:30 -04:00
__tests__ 🧹 feat: Eager HITL Checkpoint Cleanup (Expiry + Deletion) & Full-Wiring E2E (#14123) 2026-07-05 11:29:30 -04:00
admin 📒 feat: Audit Log Backend for SystemGrant Assign and Revoke Events (#13087) 2026-06-18 15:42:33 -04:00
agents 🪝 feat: Human-in-the-Loop Runtime - Tool Approval + Ask-User-Question (Slice B) (#13942) 2026-06-29 16:56:41 -04:00
assistants 🧭 fix: Tighten Action OAuth Endpoint Validation (#13142) 2026-05-15 14:53:41 -04:00
files 🗜️ fix: Support Windows ZIP MIME Uploads (#13794) 2026-06-16 11:19:06 -04:00
types
accessPermissions.js 🔗 feat: Add Granular Access Control to Shared Links via ACL System (#13051) 2026-06-03 14:17:17 -04:00
accessPermissions.sharePolicy.test.js 🔗 feat: Add Granular Access Control to Shared Links via ACL System (#13051) 2026-06-03 14:17:17 -04:00
accessPermissions.test.js 📦 refactor: Consolidate DB models, encapsulating Mongoose usage in data-schemas (#11830) 2026-03-21 14:28:53 -04:00
actions.js fix: Extend and Decouple MCP OAuth Flow Timeouts (#13622) 2026-06-09 17:50:02 -04:00
apiKeys.js 📦 refactor: Consolidate DB models, encapsulating Mongoose usage in data-schemas (#11830) 2026-03-21 14:28:53 -04:00
auth.2fa-ratelimit.test.js 🪣 refactor: Rate-Limit Token Routes and Cap Remote File Downloads (#13978) 2026-06-26 12:19:03 -04:00
auth.cloudfront.test.js 🪣 refactor: Rate-Limit Token Routes and Cap Remote File Downloads (#13978) 2026-06-26 12:19:03 -04:00
auth.js 🪣 refactor: Rate-Limit Token Routes and Cap Remote File Downloads (#13978) 2026-06-26 12:19:03 -04:00
auth.reset-password-ratelimit.test.js 🪣 refactor: Rate-Limit Token Routes and Cap Remote File Downloads (#13978) 2026-06-26 12:19:03 -04:00
balance.js 🤫 chore: Quiet Repetitive Log Noise from Balance, CloudFront, and Capability Paths (#13461) 2026-06-01 20:40:16 -04:00
banner.js 📦 refactor: Consolidate DB models, encapsulating Mongoose usage in data-schemas (#11830) 2026-03-21 14:28:53 -04:00
categories.js 📦 refactor: Consolidate DB models, encapsulating Mongoose usage in data-schemas (#11830) 2026-03-21 14:28:53 -04:00
config.js 🥷 feat: Add showInMenu Option to Model Specs (#14034) 2026-06-30 19:32:59 -04:00
convos.js 🧹 feat: Eager HITL Checkpoint Cleanup (Expiry + Deletion) & Full-Wiring E2E (#14123) 2026-07-05 11:29:30 -04:00
endpoints.js ♻️ refactor: Compute Context Gauge Client-Side, Drop Projection Endpoint (#13953) 2026-06-25 15:29:31 -04:00
index.js 📒 feat: Audit Log Backend for SystemGrant Assign and Revoke Events (#13087) 2026-06-18 15:42:33 -04:00
keys.js 🔱 chore: Harden API Routes Against IDOR and DoS Attacks (#11760) 2026-02-12 18:08:24 -05:00
mcp.js 🔐 fix: Honor Admin-Panel MCP Allowlist Overrides Without Restart (#13814) 2026-06-17 20:14:53 -04:00
memories.js 📦 refactor: Consolidate DB models, encapsulating Mongoose usage in data-schemas (#11830) 2026-03-21 14:28:53 -04:00
messages.js 🪭 feat: Add opt-in Langfuse fanout gateway + collector (#13872) 2026-06-26 11:26:39 -04:00
models.js
oauth.js 🩻 refactor: Replace Opaque OAuth Errors with Structured Failure Diagnostics (#13471) 2026-06-02 15:06:42 -04:00
oauth.test.js feat: Immediate Conversation Title Generation (#13395) 2026-06-02 16:40:57 -04:00
presets.js 🧹 chore: Cleanup Logger and Utility Imports (#9935) 2025-10-01 23:30:47 -04:00
projects.js 🗂️ feat: Add Private Chat Projects (#13467) 2026-06-03 15:29:18 -04:00
prompts.js 📁 refactor: Prompts UI (#11570) 2026-03-22 16:56:22 -04:00
prompts.test.js 📁 refactor: Prompts UI (#11570) 2026-03-22 16:56:22 -04:00
roles.js perf: Skip Role Route Capability Probe for Own and Default Roles (#14073) 2026-07-02 10:45:41 -04:00
rum.js 📈 fix: Isolate RUM Telemetry Proxy Auth from App Auth (#13765) 2026-06-15 12:49:44 -04:00
search.js 🧹 chore: Cleanup Logger and Utility Imports (#9935) 2025-10-01 23:30:47 -04:00
settings.js 🧰 feat: Redesign Agent Builder with Unified Tools Marketplace, Skills & Orchestration (#13952) 2026-07-05 11:30:12 -04:00
share.js 🔄 feat: Continue Shared Conversations as Personal Copies (#13714) 2026-06-24 16:27:01 -04:00
skills.js 🧬 feat: Add GitHub Skill Sync (#13293) 2026-06-10 21:05:54 -04:00
skills.tenant.test.js 🧵 fix: Preserve Upload Context Across Multipart Routes (#13072) 2026-05-11 15:46:48 -04:00
skills.test.js 🧬 feat: Add GitHub Skill Sync (#13293) 2026-06-10 21:05:54 -04:00
static.js 🧹 chore: Cleanup Logger and Utility Imports (#9935) 2025-10-01 23:30:47 -04:00
tags.js 📦 refactor: Consolidate DB models, encapsulating Mongoose usage in data-schemas (#11830) 2026-03-21 14:28:53 -04:00
user.js 🪣 refactor: Rate-Limit Token Routes and Cap Remote File Downloads (#13978) 2026-06-26 12:19:03 -04:00
user.verify-ratelimit.test.js 🪣 refactor: Rate-Limit Token Routes and Cap Remote File Downloads (#13978) 2026-06-26 12:19:03 -04:00