From bf649997fa44dcb97360e5356e267293c68dc19f Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Thu, 18 Jun 2026 01:40:04 +0200 Subject: [PATCH 1/4] docs: expand temporary chat page with data retention and ephemeral mode - Rewrite the temporary chat feature page into a combined Temporary Chat & Data Retention guide covering retentionMode, the three modes, the behavior matrix, save-path coverage, migration, and an FAQ - Document the new ephemeral retention mode in the interface config reference and align retainAgentFiles notes - Update the activation steps for the new top-right Temporary Chat button and add screenshots --- .../object_structure/interface.mdx | 30 ++++++++++++++---- .../temporary-chat-button-active.png | Bin 0 -> 5420 bytes .../temporary-chat/temporary-chat-button.png | Bin 0 -> 5335 bytes .../temporary-chat-input-active.png | Bin 0 -> 15757 bytes 4 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 public/images/temporary-chat/temporary-chat-button-active.png create mode 100644 public/images/temporary-chat/temporary-chat-button.png create mode 100644 public/images/temporary-chat/temporary-chat-input-active.png diff --git a/content/docs/configuration/librechat_yaml/object_structure/interface.mdx b/content/docs/configuration/librechat_yaml/object_structure/interface.mdx index 8cd12438c..35bd7ed56 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/interface.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/interface.mdx @@ -1147,7 +1147,7 @@ interface: ## retentionMode -Controls which data receives retention deadlines. +Controls which data receives retention deadlines, and whether every chat is forced to be temporary. **Key:** @@ -1156,7 +1156,7 @@ Controls which data receives retention deadlines. [ 'retentionMode', 'String', - 'Set to "temporary" to apply retention only to temporary chats, or "all" to apply retention to all supported retained data, including persistent agent resource files unless retainAgentFiles is true.', + 'Retention policy. "temporary" applies retention only to chats users mark temporary; "all" applies retention to every conversation and message while keeping them visible; "ephemeral" forces every chat to be temporary (hidden from history and search, toggle locked on).', 'retentionMode: "temporary"', ], ]} @@ -1164,10 +1164,18 @@ Controls which data receives retention deadlines. **Default:** `temporary` +**Modes:** + +- **`temporary`** _(default)_: only chats a user marks temporary expire. Normal chats never expire. +- **`all`**: every chat and message gets an `expiredAt` but stays visible and searchable until it expires. +- **`ephemeral`**: every chat is forced temporary, hidden from history and search, and the toggle is locked on. Enforcement is server-authoritative. + +See the [Temporary Chat & Data Retention](/docs/features/temporary_chat#data-retention) feature page for the full behavior matrix and migration guidance. + - `retentionMode: "all"` applies retention deadlines beyond temporary chats, including persistent - agent resource files unless `retainAgentFiles: true` is configured. Confirm your retention policy - before enabling it. + `retentionMode: "all"` and `"ephemeral"` apply retention deadlines beyond temporary chats, + including persistent agent resource files unless `retainAgentFiles: true` is configured. Confirm + your retention policy before enabling either. **Example:** @@ -1179,6 +1187,14 @@ interface: retentionMode: 'all' ``` +To force every chat to be temporary and never persisted long-term: + +```yaml filename="interface / retentionMode (ephemeral)" +interface: + temporaryChatRetention: 24 + retentionMode: 'ephemeral' +``` + ## retainAgentFiles Controls whether persistent agent resource files are exempt from all-data retention. @@ -1190,7 +1206,7 @@ Controls whether persistent agent resource files are exempt from all-data retent [ 'retainAgentFiles', 'Boolean', - 'When true, persistent agent resource files do not expire under retentionMode: "all". Non-agent files and message attachments still expire.', + 'When true, persistent agent resource files do not expire under retentionMode: "all" or "ephemeral". Non-agent files and message attachments still expire.', 'retainAgentFiles: false', ], ]} @@ -1200,7 +1216,7 @@ Controls whether persistent agent resource files are exempt from all-data retent **Notes:** -- This setting only changes behavior when `retentionMode` is set to `"all"`. +- This setting only changes behavior when `retentionMode` is set to `"all"` or `"ephemeral"`. - Set this to `true` when agents should keep their persistent resource files even while conversations, messages, and non-agent files receive retention deadlines. **Example:** diff --git a/public/images/temporary-chat/temporary-chat-button-active.png b/public/images/temporary-chat/temporary-chat-button-active.png new file mode 100644 index 0000000000000000000000000000000000000000..36b41febd3544ca1f04ae1dfe7555b936deb9b54 GIT binary patch literal 5420 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≷UC)&9}&ca+r3KzPCvVVeQqE<5fq`m9~?`1>_ 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 literal 0 HcmV?d00001 diff --git a/public/images/temporary-chat/temporary-chat-button.png b/public/images/temporary-chat/temporary-chat-button.png new file mode 100644 index 0000000000000000000000000000000000000000..28811092cec4c792e822a646f43516d02718d925 GIT binary patch literal 5335 zcmb_gWmJ@1v>sAofI$(498n1g0sW*yI)x#Hkr)`1kQ%y?M%qtNLFp2Zl9p~HBnBh} z1|%e82q^*YnS0l|KkmIh?^+Y9Hvf3P_80!84-PY`4+Kamv;TD> zzjx2GDOrC!{$AQ--&0dHpT|f;!%x*sP}qwE7OJ~HKG8O|eHuPWLad!h+A$1}4tyG0 zyXUc5KfJ$%-}0aTBfC~R@IB-4tS)Y}4tp`rli&f&5E9m`u(mRfU z*~HP((Bz4r&) z=9)!D9i5$I85tRiY1?PsMpwnYROv7${H20FMtn6nYrXjJOk*TSenHiLW zaU58^0k`H@GvlljTHv)uAlN?|1{=ik<{MDEy1F`4&Wfh$&~JNC$x#mTN*U?>rvK*g zpgB@zIe@O=x9i1Qf9TRbXLti2JMnk=R#qay%-KQEG#TeIgCaM+#bIn#^R-TEtT9GCR;^zaK~(h#I5?=R7HF*%oE zOt5mJAz^cNY?C;vkMGx;3!m^%F)^{JD!U}n$jC^|cb+kGo3J4VM7Spt2I}+O>rHk2 zP)A3H8@_`g>lS>7Q_7wE@#DvY{e3dXtCW=I8?(8eKci4Lv(U-(9%`cVK}Qx5k&)bY z?iiqWE?>D4{^0|^(_Fnim43i9ZIlw~eoV=3wrP`ZWp#hgiyP{0`>PLb^6|+8`A%?9 zgnJfMRETmjB_2S)3QDewSFiGvdb6=(g*=U7J>eK=v;S{LoJC+DtiQkC z?U-PVSG$>!nVAWT`t<3OI70)f6CU1;!>FDNV1Mg4fqVWvkziKR(gMp{|z9CqI7fp2VXK9UPl1CMv61@C`NPaS#^-Jwk! z9n=I7QWJbFu6BO6(4Z&_e2fJ0jfLG0(u!|WQ-*9e zO*^RpFMTvAsix-E%}4Ts``LiK0u;BfC&<{=#^T~)8ekI>&C+F)lB+~pi;LaY1wGB# zpe=>#Tf5xchvVbp)u$GXx9KR;T$1_nN@{93KMTQ!b_RIzN_OScw40*_!a@t&M&v25 zmrP1(x{+CeVDF6;b#kBofk({U`X3(QzGLoP%JlR!A*{b&%OT}seZ6E?S63SjXNcml zsWeSaO?~b>TdP^3!AA>)su&nt=GDuHmk&CHKm-H?+z!_D^YZhv^YT>e*{@!W1n38J zVf|~aVd(Xkm;cc(ItB)Y>CJ+<+TQi=jS`e}Y~<;>m(q2kxs{`?-MmSDG#?-m78Vw< zrx;F|?XxpKR`^m^+`5B2@cj3rhK5GlGZL~aB!3&0gOrq%aJE0Z-1p+fTT$z^~_HW;5gv7#COK z@v-kjDBaL4OV-yKUM_%3EUn_E)V5i|u{G!|Fjnay{{^ z;i_@W*55vw<+#t+W0zr!jG@KF0_(s1Z}RY1uMVaXj*isz^@yXKV5Za9MuLPbNP(M0g# z{KyI~HI!L6xv6hpU{mGNBr)$xc7;z@B{*2#27}q%A6B6Cnk=*EOucI-`eYD3=P@h? zQdu(iOj1c%8E|&w#)jk8Y#jqom6)WYULceIInix0qV;B3C_$i1jkdW*P`^ zT})zP&-u|pQgSlPyuqEqv4%}vUS8?lw+|DJ*@abNwtcYGSj|FQWhmLDJEbPGWe)wX zZhg$li(rLPG9wVKhC4eu!`|C7-8#Hio|Y9C$2tSOv1dUbhM|;X0|Nt??(S|SnUaZq zcX#)xN3PA?j!&PeuCRz$+A=aScHBwil<5Hv&el9-xeJHp)T*kgZhhg)WGbCK-d&y^ zR`@#za&qLgSdYtGef!eVl8Q5^T1*`rZvENqMMNIrLP}k$fjDf1WrGZx_b4h z(@KAec=_(ubk){O&C__Xo{fzSQxuAApugY7q$Gt?))#r;Q-c!L*4D;=MBb`f2*zAo zT!{akDL9f+P{;%n`Z_Jm(QsH#@L`!P%WZSCjQ19-)KFiavC(%oXZ;==N?99x?mxOO z;W|GUuZF35coMR+^W`OwTW6qm@!lbCE$oE&n z8q(4-ab@7ma%C@9XEY+13ZkK-)7244tGcbMq(lHaMgu^Z*1K_EoNkK5bILG_G#^|B zZi;$-g^xxit}~jUH%_F5-@ipGzayUYuG_CUsjlAM8)9ONt!I0*QFQE47stjVdAgdCrq+8h(`Q+2KgW+BsOKJ$K; z*b*q8PL_2O@SWJ7V?13wJvLo2jK{~zNq`U;+1cY_VyH&l0obf-P?f+9O$TGz$6Hmy z$?x9L=8ndIyAjdRaWhG*cPTk~@c@6KYzaBi^KZp4i<_HqdwcHhr99M7!oEArN22}* z_Cly?4I_EabtJ$Ws6{XrXD5AMzJ%7*Nn`~4lCnMrNQr;@7B1RT;XErI4;Le?tgHmK zC=dvp3^#7yreFJ-uB@d+L(eHq4w3X+PbOGODc4b{si=_WoXIF1C>b?tS3{On4vUCCKUw-z93ueI=!^k%`{!ZtI=-=Hu0O zuA+8dIez^3(YCN)1z#n=F;gu;GR(KlW6u8^ErZZM8@2EHnl1w>k>`NiZ680*uBd>O zH|@~`|2_8sftiV46BHDz^xd@qR8GBJRaJ#u>A!lgImwWua8W-ZE-lUG-^>LNFX^@M z%3f;dyVs-z;qWl39o_a5SC~IhDj*`F?&v5`>ogq}eu?2a4-dt|GV{>#auKee1ARyv z0Dc^B$49GHt~eGEHEU~bQ0-I%9J!27P6Bp?tK~9IPfvHi#?YcvJ1KWPwN2EmjR87Z^j3D*>0O=Bapw9{cDNGAo5?jHM zpcXFWv3fsu^nQ_%%}ADF&Y`ifF@OqV3TuMedr2%QXi4Dr9A6>1SXrqN2*laxX1Vw< zwg4b*^shb^E2gETwTQ=uX2=DQLO@AcY5V1}(@eFdJqs5XeX}LdLk8elJ^me`@7Li( zEhsGH>q+E{1AIE_2?CyNSu&xOIpab{M_2E)`MMeo91kixVjlu&>+QV+uJa2Er-*kW zLe4_LO9vYhw4h9VX);SiPv4`C2#N>`Bc1!~MVp_WKh@-SH;SH9z}azfce$5{(m9`n zAh?7J$3JXzYKa`wpaF8^XJcmvIfh?Z;eoQqC(z^93JzZEDKdw&`+3_=)YMUA?4%mY*cz5`Ismb!ePh8*NVAp_1 zYdlaDjd!ytFJFdRg`8gnJMIRQ%gD)@&>ns%7igAx5?6{i%Lz~%Vu)LU{@DEJdokvy z2$U)#=+G>hRHVjnLg3@0I{NJFY_Rq2wak!2AoW6zYCm=dA?!Ap+kvB)g_vo9GyrnB zCX=6+7ZatynQtV3-`o@wR=a;6@=A-Re_$ZAAX`~Gvkaga6yi!?CncC=0Ac0w$>qJ3 z0l1w1Kg0xUI@=on#=jEx(g0-u@Q#@K4-MJFDPlb?iCt1D*%>|AU(-h-Apk25xB|@* zihm!FE~foAR~ zdSko@lp;AEOu~2(iw_?@z#9?RFRd@{slYioP$ z+BJxupWjr22Ok8z`K|Q$XJO{z+FEpcJoKYk6=iwrg*1?9QSU8NCKeV9aNbz=tYpBU z5U^9sah!kadm{@VMP)TL$~$-NWR2SA4Lve8H;)G$Syss33%Ixwd~bjMMM?^fGw$8Hv@K$3ie=Rj<4+`2^_8X5|ClF7ipKm~&biv;cuNvuznBmVvO zUjpFj>wxfD&kxxx1GewI%QXgWaIbK{@q*S)C-n{mB9K6`I-HqQ^00hquEAq$mHy;c z;|^LBj;=vr_kL(P)L0NT^IslqBog@yL3aCi)`4AU7!R}ZRf;Izm4+g!7?&YcVjXAr<&vcJa-fna+#%Jb*V9d67d#>B=d zWy%Mk@1#atL47?~d1JNoLY+$y1Y>_I#Jkgq{2Ky%Br3Wk#&F>s%L@ZL9R9mU1RW6KBcl2uXm`-)&`rBxCHk^1bL`TDJQBwEqv1M2$YH1Ih zHLWMB&mU8w(TNseS}#Tu_+ecWC|dGz?Qqb~xu1NM;PxT?KYHB%)%5=VURVxs-3hfC UP(@LL!$^pxs;)|z5<2WZ09v{iHUIzs literal 0 HcmV?d00001 diff --git a/public/images/temporary-chat/temporary-chat-input-active.png b/public/images/temporary-chat/temporary-chat-input-active.png new file mode 100644 index 0000000000000000000000000000000000000000..795063fa820f7cd2e33b2a2eca643b796f85e959 GIT binary patch literal 15757 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 literal 0 HcmV?d00001 From 19ed270a8698aa0df47854f8e10e2825b057e07c Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:16:21 +0200 Subject: [PATCH 2/4] docs: Document recent dev changes and rewrite temporary chat retention Cover the user-facing and admin-facing changes merged to LibreChat dev over the last two weeks: required two-factor authentication, passkeys, email address change, ephemeral retention mode, the redesigned message composer, chat list filters, unread replies and notifications, project instructions and files, conversation starters in the Agent Builder, the Agent Marketplace, undocking artifacts, Bash output rendering, theme appearance keys and roles, config override validation, and the new librechat.yaml keys. Rewrite the temporary chat page against the merged retention code, drop the outdated screenshots, and fix pages that still described the old attach and MCP dropdowns. --- .../authentication/OAuth2-OIDC/azure.mdx | 2 +- .../configuration/authentication/email.mdx | 46 +++ .../configuration/authentication/index.mdx | 62 ++++ .../configuration/authentication/meta.json | 2 +- .../configuration/authentication/passkeys.mdx | 142 +++++++++ content/docs/configuration/dotenv.mdx | 198 ++++++++++++- .../configuration/librechat_yaml/example.mdx | 22 ++ .../object_structure/config.mdx | 274 +++++++++++++++++- .../object_structure/interface.mdx | 174 ++++++++++- .../object_structure/mcp_servers.mdx | 7 +- .../object_structure/model_specs.mdx | 4 +- .../librechat_yaml/object_structure/theme.mdx | 66 ++++- .../object_structure/web_search.mdx | 12 +- content/docs/configuration/mod_system.mdx | 32 ++ .../pre_configured_ai/bedrock.mdx | 2 +- content/docs/configuration/sharepoint.mdx | 8 +- content/docs/features/admin_panel.mdx | 22 ++ content/docs/features/agents.mdx | 50 +++- content/docs/features/artifacts.mdx | 8 + content/docs/features/authentication.mdx | 21 ++ content/docs/features/code_interpreter.mdx | 2 + content/docs/features/composer.mdx | 141 +++++++++ content/docs/features/mcp.mdx | 18 +- content/docs/features/memory.mdx | 2 +- content/docs/features/meta.json | 1 + content/docs/features/navigation.mdx | 40 ++- content/docs/features/ocr.mdx | 4 +- content/docs/features/projects.mdx | 102 +++++-- content/docs/features/search.mdx | 2 + content/docs/features/settings.mdx | 24 +- content/docs/features/temporary_chat.mdx | 234 +++++++++++---- content/docs/features/upload_as_text.mdx | 10 +- content/docs/features/web_search.mdx | 2 +- content/docs/mcp_servers/google_workspace.mdx | 2 +- content/docs/mcp_servers/salesforce.mdx | 2 +- .../temporary-chat-button-active.png | Bin 5420 -> 0 bytes .../temporary-chat/temporary-chat-button.png | Bin 5335 -> 0 bytes .../temporary-chat-input-active.png | Bin 15757 -> 0 bytes 38 files changed, 1579 insertions(+), 161 deletions(-) create mode 100644 content/docs/configuration/authentication/passkeys.mdx create mode 100644 content/docs/features/composer.mdx delete mode 100644 public/images/temporary-chat/temporary-chat-button-active.png delete mode 100644 public/images/temporary-chat/temporary-chat-button.png delete mode 100644 public/images/temporary-chat/temporary-chat-input-active.png diff --git a/content/docs/configuration/authentication/OAuth2-OIDC/azure.mdx b/content/docs/configuration/authentication/OAuth2-OIDC/azure.mdx index 901861fb0..dff50398e 100644 --- a/content/docs/configuration/authentication/OAuth2-OIDC/azure.mdx +++ b/content/docs/configuration/authentication/OAuth2-OIDC/azure.mdx @@ -184,7 +184,7 @@ SHAREPOINT_PICKER_GRAPH_SCOPE=Files.Read.All ### Usage When properly configured: -1. Users will see "From SharePoint" option in the file attachment menu +1. Users will see a **From SharePoint** option in the **Attach** section of the [composer's **+** palette](/docs/features/composer#add-files) 2. Clicking it opens the native SharePoint file picker 3. Users can browse and select files from any SharePoint site or OneDrive they have access to 4. Selected files are downloaded and attached to the conversation diff --git a/content/docs/configuration/authentication/email.mdx b/content/docs/configuration/authentication/email.mdx index 27e5eb49e..b1ae82ce9 100644 --- a/content/docs/configuration/authentication/email.mdx +++ b/content/docs/configuration/authentication/email.mdx @@ -203,6 +203,52 @@ EMAIL_FROM_NAME=LibreChat ALLOW_PASSWORD_RESET=true ``` +## Email Address Change + + + Newer than **v0.8.8**. Available now on LibreChat's `dev` and `canary` branches, and in the next release. + + +Users with a local (email and password) account can change their registered email address themselves from **Settings > Account**. The feature is on by default and needs working email delivery (Mailgun or SMTP, configured above): without it, the option is hidden. + +### User flow + +1. In **Settings > Account**, next to **Email address**, the user selects **Change**. +2. In the **Change email address** dialog, they enter the **New email address** and their **Current password**, then select **Send verification link**. +3. LibreChat first sends a security notice ("Email change requested") to the current address, with the requested address and the request IP. It sends this before checking the password, so the account owner hears about every attempt, including rejected ones. If the request passes the checks below, a verification link goes to the new address. +4. The address changes only when the link is opened. Both the old and new addresses then receive a "Your email address was changed" notice, and the new address is marked as verified. + +The request is rejected when the password is wrong, the new address equals the current one, the new address already belongs to another account, or its domain is not in [`registration.allowedDomains`](/docs/configuration/librechat_yaml/object_structure/registration#alloweddomains). Accounts that sign in through OAuth, OpenID Connect, SAML, or LDAP cannot use this flow. + +The verification link is single-use and expires after `tokenTTLSeconds` (15 minutes by default). It also stops working if the password or email of the account changes before it is opened. Completing a change invalidates any password reset links issued for the previous address. + +### Configuration + + + +In `librechat.yaml`, the `emailChange` block takes precedence over `ALLOW_EMAIL_CHANGE` and also sets the link lifetime: + +```yaml filename="librechat.yaml" +emailChange: + enabled: true + tokenTTLSeconds: 900 # 60 to 86400, default 900 (15 minutes) +``` + +Each field falls back independently: `enabled` to `ALLOW_EMAIL_CHANGE` and then `true`; `tokenTTLSeconds` to `900`. Rate limits for requesting a change and for opening links are set under [`rateLimits.emailChange` and `rateLimits.emailChangeConfirm`](/docs/configuration/librechat_yaml/object_structure/config#ratelimits), or with the matching [environment variables](/docs/configuration/dotenv#email-change-rate-limiting). + + +Set `ALLOW_EMAIL_CHANGE=false` (or `emailChange.enabled: false`) until every node runs a version that includes this feature. Older nodes issue and accept password reset links that are not bound to an address, so a link held by the previous owner of an address could outlive the change and reset the renamed account. + + ## Troubleshooting ### Mailgun Issues diff --git a/content/docs/configuration/authentication/index.mdx b/content/docs/configuration/authentication/index.mdx index 86e92576f..b9dae82aa 100644 --- a/content/docs/configuration/authentication/index.mdx +++ b/content/docs/configuration/authentication/index.mdx @@ -60,6 +60,68 @@ Quick Tips: alt="User registration screen" /> +Related sign-in options for local accounts: + +- [Passkeys](/docs/configuration/authentication/passkeys): passwordless sign-in with a device screen lock or security key (`ALLOW_PASSKEY_LOGIN`). +- [Email address change](/docs/configuration/authentication/email#email-address-change): lets users change their registered email from **Settings > Account** (`ALLOW_EMAIL_CHANGE`, on by default). + +## Required Two-Factor Authentication + + + Newer than **v0.8.8**. Available now on LibreChat's `dev` and `canary` branches, and in the next release. + + +Users can always turn on two-factor authentication (TOTP) themselves from **Settings > Account**. To make it mandatory, set: + +```bash filename=".env" +ENFORCE_TWO_FACTOR_AUTHENTICATION=true +``` + +**Who it applies to:** local (email and password) and LDAP accounts. Accounts that sign in through OAuth, OpenID Connect, or SAML are not affected, because their identity provider is responsible for MFA. A federated account that tries to sign in with a password while enforcement is on is told to use its identity provider instead. + +**What users see:** a user without 2FA who signs in (with a password, LDAP credentials, or a passkey) gets no session until setup is complete. They land on a **Two-Factor Authentication Required** screen ("Your administrator requires two-factor authentication. Set it up before continuing."), scan a QR code with an authenticator app, enter a code to verify, and save their backup codes. Users who are already signed in are moved into the same setup the next time their session is checked or refreshed, and access tokens issued before enrollment stop working. The setup session lasts 10 minutes; if it expires, the user returns to the login page and starts again. + +**After enrollment:** the **Disable 2FA** control in **Settings > Account** shows **Required by administrator**, and the server rejects attempts to disable 2FA while the policy is on. Users can still regenerate backup codes. + + + + +`ENFORCE_TWO_FACTOR_AUTHENTICATION` and the `TWO_FACTOR_TEMP_*` and `TWO_FACTOR_SETUP_*` limits are process-wide `.env` settings. They apply before a request or tenant configuration is available, so they cannot be set in `librechat.yaml` or per tenant. Set the same values on every replica. The separate budget for managing 2FA from settings is [`rateLimits.twoFactorManagement`](/docs/configuration/librechat_yaml/object_structure/config#ratelimits). + + ## Session Expiry and Refresh Token - Default values: session expiry: 15 minutes, refresh token expiry: 7 days diff --git a/content/docs/configuration/authentication/meta.json b/content/docs/configuration/authentication/meta.json index caf654b81..b8fdeaf7f 100644 --- a/content/docs/configuration/authentication/meta.json +++ b/content/docs/configuration/authentication/meta.json @@ -1,5 +1,5 @@ { "title": "Authentication", "icon": "Lock", - "pages": ["email", "ldap", "OAuth2-OIDC", "SAML"] + "pages": ["email", "passkeys", "ldap", "OAuth2-OIDC", "SAML"] } diff --git a/content/docs/configuration/authentication/passkeys.mdx b/content/docs/configuration/authentication/passkeys.mdx new file mode 100644 index 000000000..787e42d25 --- /dev/null +++ b/content/docs/configuration/authentication/passkeys.mdx @@ -0,0 +1,142 @@ +--- +title: Passkeys +icon: KeyRound +description: Let users sign in without a password using a device screen lock or a security key (WebAuthn). Covers enabling passkeys, the relying party settings, enrollment limits, and how passkeys interact with two-factor authentication. +--- + +Passkeys let users with a local (email and password) account sign in with their device screen lock, a password manager, or a hardware security key instead of typing a password. LibreChat implements them with WebAuthn. They are off by default. + + + Newer than **v0.8.8**. Available now on LibreChat's `dev` and `canary` branches, and in the next release. + + +Use passkeys when you want a phishing-resistant, passwordless sign-in for local accounts. Accounts that sign in through OAuth, OpenID Connect, SAML, or LDAP keep using their provider and cannot add passkeys. + +## Enable passkeys + + + + +**Serve LibreChat over HTTPS.** Browsers only allow WebAuthn in a secure context. `http://localhost` is exempt, so local testing works without TLS. + + + + +**Turn the feature on in `.env`.** For a standard deployment, this is the only required setting. The relying party ID and allowed origins are derived from `DOMAIN_CLIENT` and `DOMAIN_SERVER`. + +```bash filename=".env" +ALLOW_PASSKEY_LOGIN=true +``` + + + + +**Pin the relying party ID (recommended).** Each passkey is permanently bound to the RP ID it was created under. If `DOMAIN_CLIENT` might ever change, set `PASSKEY_RP_ID` now so existing passkeys keep working. + +```bash filename=".env" +PASSKEY_RP_ID=chat.example.com +``` + + + + +**Restart LibreChat.** The login page shows **Sign in with a passkey**, and **Settings > Account** shows a **Passkeys** section. + + + + +## Configuration reference + + + +### Per-user limit in `librechat.yaml` + +You can also set the enrollment cap in `librechat.yaml`: + +```yaml filename="librechat.yaml" +passkeys: + perUserMax: 10 +``` + +The cap resolves in this order: `passkeys.perUserMax` in `librechat.yaml`, then `MAX_PASSKEYS_PER_USER`, then the default of `20`. Values outside `1` to `100` are ignored and the next source is used. When a user reaches the cap, **Settings > Account** shows "You have reached the maximum number of passkeys". See [`passkeys`](/docs/configuration/librechat_yaml/object_structure/config#passkeys) in the config reference. + +## What users see + +**Adding a passkey** + +1. Open **Settings > Account**, find **Passkeys**, and select **Manage**. +2. Select **Add passkey**. +3. Enter the account password in the **Confirm your password** dialog. A passkey is a complete sign-in on its own, so LibreChat asks for the password before creating one. +4. Complete the browser or device prompt. The new passkey appears in the list with a default name such as **This device**, **Phone or tablet**, or **Security key**. + +Each entry shows when it was added and last used, and a **Synced** badge when the authenticator reports that the passkey is backed up (for example, by a password manager). Users can rename a passkey, and removing one (**Remove passkey**) also asks for the account password. + +**Signing in** + +On the login page, users select **Sign in with a passkey** and approve the device prompt. If the account has two-factor authentication enabled, LibreChat still asks for the 2FA code afterward, exactly as it does after a password sign-in. + +## Behavior and caveats + +- **Local accounts only.** Passkey enrollment and sign-in are limited to local accounts. Accounts created through an identity provider or LDAP must keep authenticating through that provider. +- **Works with email login disabled.** The **Sign in with a passkey** button and its routes depend only on `ALLOW_PASSKEY_LOGIN`. With `ALLOW_EMAIL_LOGIN=false`, existing local users can still sign in with passkeys they enrolled earlier. +- **Two-factor authentication.** Passkey sign-in goes through the same 2FA gate as password sign-in. With [`ENFORCE_TWO_FACTOR_AUTHENTICATION=true`](/docs/configuration/authentication#required-two-factor-authentication), a user who has not enrolled in 2FA is sent to the setup flow after signing in with a passkey. +- **Changing the RP ID orphans passkeys.** Passkeys created under one RP ID never work under another. Changing `PASSKEY_RP_ID`, or changing `DOMAIN_CLIENT` while `PASSKEY_RP_ID` is unset, leaves every existing passkey unusable; users must sign in another way and enroll again. +- **Origins must match.** If users reach LibreChat on an origin not covered by `PASSKEY_ORIGINS` (or the derived defaults), the browser shows "Passkeys are not available on this domain". Add every public origin to `PASSKEY_ORIGINS` when you serve LibreChat on more than one. +- **Password reset removes passkeys.** A completed password reset signs the account out everywhere and deletes all of its passkeys, so a passkey enrolled before the reset can no longer be used to get in. Users enroll again afterward. diff --git a/content/docs/configuration/dotenv.mdx b/content/docs/configuration/dotenv.mdx index 5c15db06b..cd3c3feec 100644 --- a/content/docs/configuration/dotenv.mdx +++ b/content/docs/configuration/dotenv.mdx @@ -1954,6 +1954,70 @@ Prevents brute force attacks and spam registrations by limiting login attempts a The login-attempt budget is shared by the local login API and top-level social or federated OAuth navigations from the same IP. A rejected API login receives the existing JSON `429` response. A rate-limited or banned `/oauth/*` browser navigation returns to `/login?redirect=false` with a localized error code instead of rendering a JSON document; `redirect=false` prevents an automatic OpenID redirect from immediately entering the limiter again. +#### Two-factor authentication rate limiting + + + +These are process-wide settings that apply before request or tenant configuration is available. See [Required Two-Factor Authentication](/docs/configuration/authentication#required-two-factor-authentication). + +#### Passkey rate limiting + + + #### Password reset and email verification rate limiting LibreChat applies separate IP-based limits to requesting an email and submitting the token from that email. This prevents repeated token guesses without forcing deployments to use the same limit for email delivery and token validation. @@ -2011,6 +2075,53 @@ LibreChat applies separate IP-based limits to requesting an email and submitting ]} /> +#### Email change rate limiting + +Limits [email address change](/docs/configuration/authentication/email#email-address-change) requests per signed-in user, and verification link openings per IP and per account. + +> Note: These can also be configured via `librechat.yaml` in the `rateLimits.emailChange` and `rateLimits.emailChangeConfirm` sections. A value set in `librechat.yaml` takes precedence over the environment variable. + + + #### Score for each violation Note: These can also be configured via `librechat.yaml` in the `rateLimits.conversationsImport` section. A value set in `librechat.yaml` takes precedence over the environment variable. + > Note: You can utilize both limiters, but default is to limit by IP only. ##### IP Limiter: @@ -2329,7 +2460,7 @@ Limits how often users can fork conversations to prevent abuse. Limits how often users can upload files to prevent abuse. -> Note: These can also be configured via `librechat.yaml` in the `rateLimits.fileUploads` section. +> Note: These can also be configured via `librechat.yaml` in the `rateLimits.fileUploads` section. A value set in `librechat.yaml` takes precedence over the environment variable. ##### IP Limiter: @@ -2373,7 +2504,7 @@ Limits how often users can upload files to prevent abuse. Limits how often users can use Text-to-Speech to prevent abuse. -> Note: These can also be configured via `librechat.yaml` in the `rateLimits.tts` section. +> Note: These can also be configured via `librechat.yaml` in the `rateLimits.tts` section. A value set in `librechat.yaml` takes precedence over the environment variable. ##### IP Limiter: @@ -2417,7 +2548,7 @@ Limits how often users can use Text-to-Speech to prevent abuse. Limits how often users can use Speech-to-Text to prevent abuse. -> Note: These can also be configured via `librechat.yaml` in the `rateLimits.stt` section. +> Note: These can also be configured via `librechat.yaml` in the `rateLimits.stt` section. A value set in `librechat.yaml` takes precedence over the environment variable. ##### IP Limiter: @@ -2503,7 +2634,9 @@ see: **[Authentication System](/docs/configuration/authentication)** All authentication settings in this section should be configured in your `.env` file, not in the `librechat.yaml` file or `docker-compose.override.yml`. The `docker-compose.override.yml` file is only used to mount volumes and set environment variables for Docker, while the `librechat.yaml` - file is used for custom endpoints and other application settings. + file is used for custom endpoints and other application settings. The exceptions are + `ALLOW_EMAIL_CHANGE` and `MAX_PASSKEYS_PER_USER`, which `emailChange` and `passkeys` in + `librechat.yaml` override when set. - General Settings: @@ -2558,6 +2691,18 @@ see: **[Authentication System](/docs/configuration/authentication)** 'Set to true to allow users to log in without verifying their email address. If set to false, users will be required to verify their email before logging in.', 'ALLOW_UNVERIFIED_EMAIL_LOGIN=true', ], + [ + 'ALLOW_EMAIL_CHANGE', + 'boolean', + 'Allow local-account users to change their email address from Settings > Account. Requires email delivery. Enabled by default if omitted. emailChange.enabled in librechat.yaml takes precedence. Keep it false during multi-node rollouts until every node supports it.', + '# ALLOW_EMAIL_CHANGE=true', + ], + [ + 'ENFORCE_TWO_FACTOR_AUTHENTICATION', + 'boolean', + 'Require local and LDAP accounts to enroll in 2FA before a full session is issued. Federated identity providers keep their own MFA policies.', + 'ENFORCE_TWO_FACTOR_AUTHENTICATION=false', + ], [ 'MIN_PASSWORD_LENGTH', 'number', @@ -2567,6 +2712,8 @@ see: **[Authentication System](/docs/configuration/authentication)** ]} /> +See [Email Address Change](/docs/configuration/authentication/email#email-address-change) for `ALLOW_EMAIL_CHANGE` and [Required Two-Factor Authentication](/docs/configuration/authentication#required-two-factor-authentication) for `ENFORCE_TWO_FACTOR_AUTHENTICATION`. + > **Quick Tip:** Even with registration disabled, add users directly to the database using `npm run create-user`. > **Quick Tip:** With registration disabled, you can delete a user with `npm run delete-user email@domain.com`. @@ -2597,6 +2744,45 @@ see: **[Authentication System](/docs/configuration/authentication)** - For more information: **[Refresh Token](https://github.com/LibreChat-AI/LibreChat/pull/927)** +- Passkey Settings: + +Passkey (WebAuthn) sign-in for local accounts. Requires HTTPS in production; `localhost` is exempt. See [Passkeys](/docs/configuration/authentication/passkeys). + + Account. +# Omitted, these fall back to ALLOW_EMAIL_CHANGE and a 15-minute link. +# emailChange: +# enabled: true +# tokenTTLSeconds: 900 + +# Passkey (WebAuthn) enrollment limits. +# Omitted, perUserMax falls back to MAX_PASSKEYS_PER_USER, then 20. +# passkeys: +# perUserMax: 20 + # Example Registration Object Structure (optional) registration: socialLogins: ['github', 'google', 'discord', 'openid', 'facebook'] @@ -488,6 +499,17 @@ registration: # ipWindowInMinutes: 60 # Rate limit window for conversation imports per IP # userMax: 50 # userWindowInMinutes: 60 # Rate limit window for conversation imports per user +# # Asking for a change of the registered email, per authenticated user. +# emailChange: +# userMax: 3 +# userWindowInMinutes: 2 +# # Opening a verification link. The endpoint is unauthenticated, so the source +# # address is bounded as well as the account the link names. +# emailChangeConfirm: +# ipMax: 20 +# ipWindowInMinutes: 2 +# userMax: 2 +# userWindowInMinutes: 2 # Source-aware content filters are disabled when omitted. `filters` is loaded # only from the base config; role, group, and user overrides cannot change it. diff --git a/content/docs/configuration/librechat_yaml/object_structure/config.mdx b/content/docs/configuration/librechat_yaml/object_structure/config.mdx index 59bb125dc..876a7289f 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/config.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/config.mdx @@ -28,6 +28,57 @@ icon: Settings ]} /> +## projects + +_Newer than v0.8.8._ + +**Key:** + + + +**Subkeys:** + + + +See [Projects](/docs/features/projects). Unknown keys inside `projects` fail validation. + +```yaml filename="projects" +projects: + maxFiles: 50 + maxInstructionsLength: 16000 + maxDescriptionLength: 1000 +``` + ## permissions Controls retry behavior for concurrent access-control-list writes. @@ -151,6 +202,23 @@ See: [Content Filter Object Structure](/docs/configuration/librechat_yaml/object See: [Legacy messageFilter](/docs/configuration/librechat_yaml/object_structure/message_filter#legacy-messagefilter) +## fileListLimit + +_Newer than v0.8.8._ + + + +Requests without a `limit` are not affected. The composer's recent files list ([`interface.composerRecentFiles`](/docs/configuration/librechat_yaml/object_structure/interface)) is capped at 100, this setting's default, so the palette never asks for more rows than a default deployment returns. + ## fileStrategy - **Options**: "local" | "firebase" | "s3" | "azure_blob" | "cloudfront" @@ -399,6 +467,50 @@ Set `secureImageLinks: false` only as a compatibility opt-out for deployments th ]} /> +## conversationList + +_Newer than v0.8.8._ + +**Key:** + + + +**Subkeys:** + + + +See [Navigation](/docs/features/navigation) for the conversation list filters. Values outside these ranges fail config validation like any other invalid key. An invalid value set through an Admin Panel override is ignored with a warning, and the defaults apply. + +```yaml filename="conversationList" +conversationList: + maxEndpointFilters: 50 + maxEndpointNameLength: 128 +``` + ## ocr **Key:** @@ -742,9 +854,29 @@ see: [File Config Object Structure](/docs/configuration/librechat_yaml/object_st ], ['stt', 'Object', 'Configures rate limits specifically for speech-to-text (stt) requests', ''], ['tts', 'Object', 'Configures rate limits specifically for text-to-speech (tts) requests', ''], + [ + 'mcpApps', + 'Object', + 'Per-user limits for MCP App browser routes, in a fixed one-minute window.', + '', + ], + [ + 'emailChange', + 'Object', + 'Limits requests to change the registered email address, per signed-in user.', + '', + ], + [ + 'emailChangeConfirm', + 'Object', + 'Limits openings of email change verification links, per IP and per account.', + '', + ], ]} /> +**Precedence:** at startup, LibreChat writes each value set under `fileUploads`, `conversationsImport`, `tts`, `stt`, `agentEvents`, `emailChange`, and `emailChangeConfirm` into the matching environment variable (prefixes `FILE_UPLOAD`, `IMPORT`, `TTS`, `STT`, `AGENT_EVENT`, `EMAIL_CHANGE`, and `EMAIL_CHANGE_CONFIRM`, with suffixes `_IP_MAX`, `_IP_WINDOW`, `_USER_MAX`, and `_USER_WINDOW`). A YAML value therefore overrides the environment variable, and a key you leave out keeps the environment value or the built-in default. `twoFactorManagement` and `mcpApps` have no environment equivalents. + **twoFactorManagement Subkeys:** +**mcpApps Subkeys:** + + + +**emailChange Subkeys:** + + + +**emailChangeConfirm Subkeys:** + + + +The confirmation endpoint is unauthenticated, so it is bounded by source address as well as by the account the link names. See [Email Address Change](/docs/configuration/authentication/email#email-address-change). + - **Example**: ```yaml filename="rateLimits" rateLimits: @@ -881,6 +1064,17 @@ This admission bucket is separate from normal message execution limits. The dura ipWindowInMinutes: 1 userMax: 50 userWindowInMinutes: 1 + mcpApps: + resourcesPerMinute: 120 + toolCallsPerMinute: 60 + emailChange: + userMax: 3 + userWindowInMinutes: 2 + emailChangeConfirm: + ipMax: 20 + ipWindowInMinutes: 2 + userMax: 2 + userWindowInMinutes: 2 ``` ## registration @@ -908,6 +1102,82 @@ see also: - [alloweddomains](/docs/configuration/librechat_yaml/object_structure/registration#alloweddomains), - [Registration Object Structure](/docs/configuration/librechat_yaml/object_structure/registration) +## emailChange + +_Newer than v0.8.8._ + +**Key:** + + Account, and how long verification links last.', + '', + ], + ]} +/> + +**Subkeys:** + + + +Each field set here takes precedence over its environment fallback. Email delivery must be configured for the option to appear. See [Email Address Change](/docs/configuration/authentication/email#email-address-change). + +```yaml filename="emailChange" +emailChange: + enabled: true + tokenTTLSeconds: 900 +``` + +## passkeys + +_Newer than v0.8.8._ + +**Key:** + + + +**Subkeys:** + + + +Passkeys themselves are enabled with `ALLOW_PASSKEY_LOGIN` in `.env`. See [Passkeys](/docs/configuration/authentication/passkeys). + +```yaml filename="passkeys" +passkeys: + perUserMax: 20 +``` + ## memory **Key:** @@ -1149,11 +1419,11 @@ see also: 'Enables or disables the "Run Code" button for Markdown Code Blocks', '', ], - ['webSearch', 'Boolean', 'Enables or disables the web search button in the chat interface', ''], + ['webSearch', 'Boolean', 'Enables or disables the Web Search tool in the composer palette', ''], [ 'fileSearch', 'Boolean', - 'Enables or disables the file search button in the chat interface', + 'Enables or disables the File Search tool in the composer palette', '', ], ['fileCitations', 'Boolean', 'Globally enables or disables file citations for all users', ''], diff --git a/content/docs/configuration/librechat_yaml/object_structure/interface.mdx b/content/docs/configuration/librechat_yaml/object_structure/interface.mdx index 35bd7ed56..8dc0acf36 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/interface.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/interface.mdx @@ -37,12 +37,18 @@ These are fields under `interface`: - `autoSubmitFromUrl` - `customWelcome` - `codeHighlightThrottleMs` +- `artifactUndocking` - `runCode` - `webSearch` - `fileSearch` - `fileCitations` - `feedback` +- `replyNotifications` - `defaultPinnedTools` +- `composerRecentFiles` +- `steerArmConfirmationTimeoutMs` +- `queuedTurnReconciliationTimeoutMs` +- `queuedSendLockTimeoutMs` - `peoplePicker` - `marketplace` @@ -129,6 +135,7 @@ interface: fireConcurrency: 5 customWelcome: 'Hey {{user.name}}! Welcome to LibreChat' codeHighlightThrottleMs: 300 + artifactUndocking: true runCode: true webSearch: true fileSearch: true @@ -137,7 +144,6 @@ interface: defaultPinnedTools: - artifacts - execute_code - - mcp ``` ## theme @@ -312,6 +318,14 @@ interface: ]} /> +### Where the policy links appear + +On the sign-in and registration screens, published policies appear as a consent sentence: "By continuing, you agree to the Terms of Service and acknowledge the Privacy Policy." If only one policy is published, the sentence names only that one. On the registration screen it sits under the submit button; on the sign-in screen it sits below the sign-in options. + +In chat, the policy links appear under the message box on the welcome screen of a new chat, and are hidden once a conversation starts. + +A policy whose `externalUrl` is empty or blank is treated as not published and is never shown. When `termsOfService.modalAcceptance` is `true`, the auth screens show plain policy links instead of the consent sentence, because users accept the terms explicitly in the dialog after signing in. + ## termsOfService **Key:** @@ -1059,14 +1073,14 @@ Controls whether the temporary chat feature is available to users. Temporary cha 'temporaryChat', 'Boolean', 'Enables or disables the temporary chat feature.', - 'When set to `false`, users will not see the option to start temporary chats.', + 'When set to false, users will not see the option to start temporary chats, unless retentionMode is "ephemeral", which shows the toggle locked on for everyone.', ], ]} /> **Default:** `true` -**Note:** The retention period for temporary chats can be configured using `temporaryChatRetention`. +**Note:** The retention period for temporary chats can be configured using `temporaryChatRetention`. Under `retentionMode: "ephemeral"` the toggle is shown, locked on, to every user regardless of this setting or the `TEMPORARY_CHAT` permission. **Example:** @@ -1077,7 +1091,7 @@ interface: ## temporaryChatRetention -The `temporaryChatRetention` configuration allows you to customize how long temporary chats are retained before being automatically deleted. +The `temporaryChatRetention` configuration allows you to customize how long temporary chats are retained before being automatically deleted. Under `retentionMode: "ephemeral"`, every chat is temporary, so this value is the lifetime of every chat. **Key:** @@ -1123,7 +1137,7 @@ interface: ## generalChatRetention -Controls how long regular chats are retained when `retentionMode` is set to `"all"`. +Controls how long regular chats are retained when `retentionMode` is set to `"all"`. It is ignored by the other modes; under `"ephemeral"` every chat is temporary and uses `temporaryChatRetention`. + +**Default:** `true` + +Setting it to `false` hides the button for new undocks. A pane that is already in its own window keeps its **Dock back to panel** button, so users can always bring it back. + +**Example:** + +```yaml filename="interface / artifactUndocking" +interface: + artifactUndocking: false +``` + ## runCode Enables/disables the "Run Code" button for Markdown Code Blocks. More info on the [LibreChat Code Interpreter API](/docs/features/code_interpreter) @@ -1329,7 +1371,7 @@ interface: ## webSearch -Enables/disables the web search button in the chat interface. More info on [Web Search Configuration](/docs/configuration/librechat_yaml/object_structure/web_search) +Enables/disables the **Web Search** tool in the [composer](/docs/features/composer) palette. More info on [Web Search Configuration](/docs/configuration/librechat_yaml/object_structure/web_search) **Note:** This setting does not disable the [Agents Web Search capability](/docs/features/agents#agent-capabilities). To disable the Agents capability, see the [Agents endpoint configuration](/docs/configuration/librechat_yaml/object_structure/agents#capabilities) instead. @@ -1339,7 +1381,7 @@ Enables/disables the web search button in the chat interface. More info on [Web @@ -1354,7 +1396,7 @@ interface: ## fileSearch -Enables/disables the file search (for RAG API usage via tool) button in the chat interface +Enables/disables the **File Search** tool (RAG API usage via tool) in the [composer](/docs/features/composer) palette. **Note:** This setting does not disable the [Agents File Search Capability](/docs/features/agents#file-search). To disable the Agents Capability, see the [Agents Endpoint configuration](/docs/configuration/librechat_yaml/object_structure/agents) instead. @@ -1364,7 +1406,7 @@ Enables/disables the file search (for RAG API usage via tool) button in the chat @@ -1445,6 +1487,51 @@ interface: feedback: false ``` +## replyNotifications + +_Newer than v0.8.8._ Controls which unread-reply alerts users are allowed to turn on. When a reply finishes while a user is looking at another chat, LibreChat marks that chat as unread. Users then choose their own alerts in **Settings > General > Notifications**; these options only decide which of those alerts are offered. + +The unread dots in the chat list and the **Mark as unread** action are always available and are not affected by this setting. + +**Key:** + + + +**Sub-keys:** + + + +Setting `tabBadge`, `desktop` or `sound` to `false` hides that option from users' settings. What each user turns on is stored per device. See [Settings](/docs/features/settings) for the user side. + +**Example:** + +```yaml filename="interface / replyNotifications" +interface: + replyNotifications: + tabBadge: true + desktop: true + sound: false + pollIntervalMs: 60000 +``` + ## defaultPinnedTools Seeds the initial prompt-bar pinned tools for users who have not customized their pinned tool state. Once a user pins or unpins a tool, LibreChat preserves that user's choice. @@ -1456,8 +1543,8 @@ Seeds the initial prompt-bar pinned tools for users who have not customized thei [ 'defaultPinnedTools', 'Array of strings', - 'Tool keys and MCP dropdown/server names that should start pinned in the prompt bar for new or uncustomized users.', - 'When omitted, built-in tools start unpinned and the MCP dropdown keeps its default pinned state.', + 'Built-in tool keys that should start pinned on the composer bar for new or uncustomized users.', + 'When omitted, built-in tools start unpinned.', ], ]} /> @@ -1465,8 +1552,8 @@ Seeds the initial prompt-bar pinned tools for users who have not customized thei **Supported values:** - Built-in tool keys: `artifacts`, `execute_code`, `web_search`, `file_search`, `skills` -- `mcp` to pin the MCP servers dropdown -- A specific MCP server name to seed that server as pinned + +The `mcp` keyword and MCP server names are still accepted for compatibility, but the redesigned [composer](/docs/features/composer) does not pin MCP servers to the bar. Users turn servers on from the palette's **MCP Servers** section instead. **Example:** @@ -1475,7 +1562,66 @@ interface: defaultPinnedTools: - artifacts - execute_code - - mcp +``` + +## composerRecentFiles + +_Newer than v0.8.8._ How many recently used files the [composer](/docs/features/composer) palette requests for its **Your files** section before the user searches. + +**Key:** + + + +**Default:** `5` + +The palette displays at most five of them, so values above `5` have no visible effect; use a lower value to shorten the list, or `0` to hide it. Searching the palette, or **Show all**, still reaches every file. The value is also capped by the top-level [`fileListLimit`](/docs/configuration/librechat_yaml/object_structure/config#filelistlimit). + +```yaml filename="interface / composerRecentFiles" +interface: + composerRecentFiles: 10 +``` + +## Queue and steer timeouts + +_Newer than v0.8.8._ Three timeouts tune how the client handles messages sent while a response is still streaming (queued messages and steers, see [Agents](/docs/features/agents)). The defaults suit most deployments; raise them when a slow proxy or a lagging database replica makes queued messages show as unconfirmed. + + + +All three must be positive integers. + +```yaml filename="interface / queue and steer timeouts" +interface: + queuedTurnReconciliationTimeoutMs: 120000 ``` ## peoplePicker diff --git a/content/docs/configuration/librechat_yaml/object_structure/mcp_servers.mdx b/content/docs/configuration/librechat_yaml/object_structure/mcp_servers.mdx index 927e7ef6c..c1846bb09 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/mcp_servers.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/mcp_servers.mdx @@ -522,12 +522,7 @@ Enable coordination only after every replica is upgraded and connected to the sa - **Usage in `headers` and `env`:** - Once defined under `customUserVars`, these variables can be referenced in the `headers` (for `sse` and `streamable-http` types) or `env` (for `stdio` type) sections using the `{{VARIABLE_NAME}}` syntax. - Users provide these values through the UI. These settings can be accessed in two ways: - - **From Assistant Chat Input**: When selecting MCP tools for an assistant, a settings icon will appear next to configurable MCP servers in the tool selection dropdown. Clicking this icon opens a dialog to manage credentials for that server. - MCP Per-User Variables Configuration - Assistant Access + - **From Chat Input**: In the **MCP Servers** section of the [composer's **+** palette](/docs/features/composer#turn-on-tools-skills-and-mcp-servers), configurable servers have a **Configure** control on their row. Choosing it opens a dialog to manage credentials for that server. Selecting a server that still needs credentials opens the same dialog. MCP Per-User Variables Configuration - Assistant Access Dialog", expected one of: librechat, clickhouse`). +A theme set through a config override (for a role, group or user in the [Admin Panel](/docs/features/admin_panel#configuration-management)) follows the same rules, with one difference: an invalid override theme falls back to the base `interface.theme` from `librechat.yaml`, not to the default theme. Those log lines start with `[getAppConfig]`, for example `[getAppConfig] Ignoring interface.theme from a config override; the base theme applies instead:`. + The `colors` and `appearance` maps work differently from the fields around them. **An unknown token is ignored, and the rest of the theme applies.** A key inside `colors` or `appearance` that this version of LibreChat does not know, whether a typo or a token added in a newer version, costs only itself. The server logs it and leaves unknown colors out of the theme it sends to the browser: @@ -140,7 +143,7 @@ The browser applies the same rules to the theme it receives and logs `[Deploymen ### Colors -Colors use the same token names as the theme engine: `rgb-` followed by the token, such as `rgb-surface-primary`, `rgb-text-primary`, `rgb-border-medium`, `rgb-accent-primary` or `rgb-status-error-subtle`. The full list of 106 tokens is `themeColorTokens` in [`packages/data-provider/src/theme.ts`](https://github.com/LibreChat-AI/LibreChat/blob/canary/packages/data-provider/src/theme.ts), which the server and the browser both read, and each token is described in the `IThemeRGB` interface in [`packages/client/src/theme/types/index.ts`](https://github.com/LibreChat-AI/LibreChat/blob/canary/packages/client/src/theme/types/index.ts). +Colors use the same token names as the theme engine: `rgb-` followed by the token, such as `rgb-surface-primary`, `rgb-text-primary`, `rgb-border-medium`, `rgb-accent-primary` or `rgb-status-error-subtle`. The full list of 130 tokens is `themeColorTokens` in [`packages/data-provider/src/theme.ts`](https://github.com/LibreChat-AI/LibreChat/blob/canary/packages/data-provider/src/theme.ts), which the server and the browser both read, and each token is described in the `IThemeRGB` interface in [`packages/client/src/theme/types/index.ts`](https://github.com/LibreChat-AI/LibreChat/blob/canary/packages/client/src/theme/types/index.ts). Beyond the surface, text, border, status and syntax palettes, these roles let a theme restyle specific interaction states and components: @@ -151,7 +154,14 @@ Beyond the surface, text, border, status and syntax palettes, these roles let a | Inverted and fixed | `rgb-surface-inverted`, `rgb-surface-inverted-hover`, `rgb-text-inverted`, `rgb-surface-fixed`, `rgb-surface-fixed-hover`, `rgb-text-fixed` | Controls drawn in the opposite mode's colors, and controls that keep one color in both modes | | Disabled | `rgb-surface-disabled`, `rgb-text-disabled`, `rgb-border-disabled` | Disabled controls, when `disabledStyle` is `fill` (see [Appearance](#appearance)) | | Control border | `rgb-border-control` | The edge of inputs, select triggers and one-time code slots, kept separate from quiet separators because it needs 3:1 contrast | +| Fields | `rgb-border-field-focus`, `rgb-field-fill`, `rgb-field-text` | A focused field's edge when `fieldFocusStyle` is `border` (follows `rgb-focus-control`), a field's fill when `fieldFillStyle` is `fill` (follows `rgb-surface-primary`), and the typed value (follows `rgb-text-primary`) | +| Primary button | `rgb-button-primary`, `rgb-button-primary-hover` | The primary Button's fill and hover; follow `rgb-surface-inverted` and `rgb-surface-inverted-hover`, which checkboxes and switches keep using | +| Inks | `rgb-dialog-title`, `rgb-badge-label` | Dialog titles and badge labels; both follow `rgb-text-primary` | | Scrim | `rgb-surface-overlay` | The color behind dialogs; its strength is set by the scrim opacities in [Appearance](#appearance) | +| Media overlay | `rgb-surface-media-overlay`, `rgb-text-on-media` | Scrims, chips and progress drawn over the user's own images (lightbox, image preview, uploads in progress), and the text on them. Bundled themes keep them black and white in both modes | +| Avatar | `rgb-avatar-fill`, `rgb-avatar-text`, `rgb-avatar-placeholder`, `rgb-avatar-edge` | The default user avatar's fill and glyph (the glyph follows `rgb-text-primary`), the backdrop behind a loading or transparent agent or assistant avatar (follows `rgb-surface-secondary` in light mode and `rgb-surface-tertiary` in dark), and the hairline around the default avatar | +| File tiles | `rgb-file-document`, `rgb-file-sheet`, `rgb-file-code`, `rgb-file-artifact`, `rgb-file-audio`, `rgb-file-video`, `rgb-file-generic`, `rgb-file-ink` | One fill per kind of file, and the glyph drawn on every tile | +| Illustration | `rgb-illustration-subtle`, `rgb-illustration`, `rgb-illustration-strong` | The three tones of in-app artwork, such as the file drop zone's illustration | | Switch | `rgb-switch-unchecked`, `rgb-switch-thumb` | The unchecked switch track, and the knob in both states | | Table | `rgb-table-header-text`, `rgb-table-header-fill` | Column names, and the opaque fill of a sticky table header | | Chart series | `rgb-series-1` through `rgb-series-8` | Categorical chart colors, in order | @@ -162,7 +172,7 @@ A few tokens follow a related token you did set when you leave them out, so a pa ### Appearance -Appearance values are set **per mode**, and a mode without them uses the defaults below. To change shape in both modes, repeat the values under `light` and `dark`, as in the example above. +Appearance values are set **per mode**, and a mode without them uses the defaults below. The defaults are the same in both modes except `menuShadow` and `tooltipShadow`, which are heavier in dark mode. To change shape in both modes, repeat the values under `light` and `dark`, as in the example above. | Key | Controls | Default | | --- | --- | --- | @@ -170,6 +180,9 @@ Appearance values are set **per mode**, and a mode without them uses the default | `roundControlRadius` | Radius of fully rounded controls | `9999px` | | `surfaceRadius` | Radius of surfaces such as cards and menus | `1rem` | | `largeSurfaceRadius` | Radius of large surfaces such as dialogs | `1.5rem` | +| `menuRadius` | Corner radius of menu panels | `0.7rem` | +| `tooltipRadius` | Corner radius of tooltips | `0.275rem` | +| `tabRadius` | Corner radius of tab triggers | `0.185rem` | | `radiusSm` | The `rounded-sm` step used across the app | `calc(0.5rem - 4px)` | | `radiusMd` | The `rounded-md` step | `calc(0.5rem - 2px)` | | `radiusLg` | The `rounded-lg` step | `0.5rem` | @@ -177,6 +190,20 @@ Appearance values are set **per mode**, and a mode without them uses the default | `radius2xl` | The `rounded-2xl` step | `1rem` | | `radius3xl` | The `rounded-3xl` step | `1.5rem` | | `controlHeight` | Height of standard controls | `2.25rem` | +| `controlPaddingX` | Inline padding of theme-sized controls; follows `spaceNormal` when unset | `0.75rem` | +| `controlGap` | Gap between a control's icon and label; follows `spaceCompact` when unset | `0.375rem` | +| `controlFontWeight` | Label weight of theme-sized controls | `500` | +| `buttonHeight` | Height of the default Button | `2.5rem` | +| `buttonHeightSm` | Height of the `sm` Button | `2.25rem` | +| `fieldHeight` | Height of form fields | `2.5rem` | +| `fieldPaddingY` | Vertical padding of form fields | `0.5rem` | +| `fieldFocusStyle` | How a focused field shows focus: `ring` draws the focus ring, `border` swaps the field's edge to `rgb-border-field-focus` | `ring` | +| `fieldFillStyle` | Whether fields stay `transparent` or paint `rgb-field-fill` (`fill`) | `transparent` | +| `labelSize` | Font size of field labels; follows `textSm` when unset | `0.875rem` | +| `labelLeading` | Line height of field labels | `1` | +| `labelFontWeight` | Weight of field labels; `inherit` keeps the weight of the surrounding text | `inherit` | +| `focusRingWidth` | Width of the keyboard focus outline | `2px` | +| `focusRingOffset` | Distance of the focus outline from the element's edge | `2px` | | `switchWidth` | Width of the switch | `2.75rem` | | `switchHeight` | Height of the switch; the knob is this minus the track's 4px border | `1.5rem` | | `tableCellSpaceY` | Vertical padding of table cells | `1rem` | @@ -199,10 +226,18 @@ Appearance values are set **per mode**, and a mode without them uses the default | `leadingLg` | Line height paired with `text-lg` | `calc(1.75 / 1.125)` | | `leadingXl` | Line height paired with `text-xl` | `calc(1.75 / 1.25)` | | `leading2xl` | Line height paired with `text-2xl` | `calc(2 / 1.5)` | +| `dialogStroke` | Width of the dialog's edge stroke | `0px` | +| `dialogPaddingX` | Inline padding of dialogs | `1.5rem` | +| `dialogHeaderGap` | Gap between a dialog's title and description | `0.375rem` | +| `dialogTitleSize` | Font size of dialog titles; follows `textLg` when unset | `1.125rem` | +| `dialogTitleLeading` | Line height of dialog titles | `1` | +| `dialogTitleFontWeight` | Weight of dialog titles | `600` | +| `dialogTitleFontFamily` | Font family of dialog titles; follows `displayFontFamily` when unset | `Inter, sans-serif` | | `scrimOpacity` | Strength of the scrim behind standard dialogs | `0.8` | | `alertScrimOpacity` | Strength of the scrim behind confirmation dialogs | `0.9` | | `modalScrimOpacity` | Strength of the scrim behind other modal dialogs | `0.65` | | `elevationSurface` | Shadow of raised theme surfaces | `0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)` | +| `elevationDrag` | Shadow of a badge while it is dragged | `0 10px 25px rgb(0 0 0 / 0.1)` | | `shadow2xs` | The `shadow-2xs` step | `0 1px rgb(0 0 0 / 0.05)` | | `shadowXs` | The `shadow-xs` step | `0 1px 2px 0 rgb(0 0 0 / 0.05)` | | `shadowSm` | The `shadow-sm` step and bare `shadow` | `0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)` | @@ -210,6 +245,8 @@ Appearance values are set **per mode**, and a mode without them uses the default | `shadowLg` | The `shadow-lg` step | `0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)` | | `shadowXl` | The `shadow-xl` step | `0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)` | | `shadow2xl` | The `shadow-2xl` step | `0 25px 50px -12px rgb(0 0 0 / 0.25)` | +| `menuShadow` | Shadow of menu panels; in light mode, follows `shadowLg` when unset | Light: `0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)`; dark: `0 10px 15px -3px rgb(0 0 0 / 0.25), 0 4px 6px -4px rgb(0 0 0 / 0.1)` | +| `tooltipShadow` | Shadow of tooltips | Light: `0 2px 4px 0 rgb(0 0 0 / 0.25)`; dark: `0 1px 2px 0 rgb(0 0 0 / 0.35)` | | `motionFast` | Duration of fast transitions | `150ms` | | `motionNormal` | Duration of normal transitions | `200ms` | @@ -217,17 +254,24 @@ The defaults reproduce LibreChat's look, so a theme that sets none of these keys Accepted values: -- **Radii, `controlHeight`, spacing and text sizes:** `0`, or a number in `px`, `rem` or `em` (such as `0.25rem`), or a single `calc()` of two such lengths (such as `calc(0.5rem - 2px)`). +- **Radii, `controlHeight`, `controlPaddingX`, `controlGap`, button and field sizes, spacing, text and label sizes, and the dialog lengths (`dialogStroke`, `dialogPaddingX`, `dialogHeaderGap`, `dialogTitleSize`):** `0`, or a number in `px`, `rem` or `em` (such as `0.25rem`), or a single `calc()` of two such lengths (such as `calc(0.5rem - 2px)`). - **`switchWidth` and `switchHeight`:** a positive length in `px` or `rem`. Both must use the same unit (a side you leave out uses its `rem` default), the width must exceed the height so the knob can travel, and the height must clear the 4px track border (more than `4px`, or at least `0.5rem`). - **`tableCellSpaceY` and `tableRowStroke`:** `0`, or a length in `px` or `rem`. +- **`focusRingWidth`:** a positive length in `px` or `rem`, so the focus indicator never disappears. +- **`focusRingOffset`:** `0`, or a length in `px` or `rem` that may be negative (drawing the outline inside the element's edge). - **`disabledStyle`:** `dim` or `fill`. -- **Line heights:** a unitless number (such as `1.5`), a single `calc()` dividing two numbers (such as `calc(1.25 / 0.875)`), or a length. +- **`fieldFocusStyle`:** `ring` or `border`. +- **`fieldFillStyle`:** `transparent` or `fill`. +- **Font weights (`controlFontWeight`, `dialogTitleFontWeight`):** a whole number from `1` to `1000`. `labelFontWeight` also accepts `inherit`. +- **Line heights (the `leading*` steps, `labelLeading` and `dialogTitleLeading`):** a unitless number (such as `1.5`), a single `calc()` dividing two numbers (such as `calc(1.25 / 0.875)`), or a length. - **Scrim opacities:** a number from `0` to `1`. - **Font families:** any non-empty `font-family` list without `;`, `{` or `}`. The font must be available to the browser: LibreChat bundles Inter, Roboto Mono and Inconsolata, so any other family has to be installed on the viewer's machine or served by your deployment, or the next family in the list is used. -- **Shadow steps (`shadow2xs` through `shadow2xl`):** a concrete `box-shadow` list, or `none`. `var()`, `env()`, `attr()` and `url()` are rejected. +- **Shadow steps (`shadow2xs` through `shadow2xl`), `menuShadow`, `tooltipShadow` and `elevationDrag`:** a concrete `box-shadow` list, or `none`. `var()`, `env()`, `attr()` and `url()` are rejected. - **`elevationSurface`:** any non-empty `box-shadow` value without `;`, `{`, `}` or `url()`. - **Motion:** a duration in `ms` or `s`, such as `120ms`. +Every appearance value must be a string. Quote numbers such as font weights, line heights and scrim opacities (`'500'`, `'1.5'`, `'0.8'`); an unquoted YAML number is rejected. + ### Brands `brands` recolors the provider icons shown next to models. It can be set once at the top level for both modes, and overridden per mode under `modes..brands`. diff --git a/content/docs/configuration/librechat_yaml/object_structure/web_search.mdx b/content/docs/configuration/librechat_yaml/object_structure/web_search.mdx index de4156dca..c6114f53c 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/web_search.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/web_search.mdx @@ -696,11 +696,9 @@ You can configure SearXNG in LibreChat within the UI or through `librechat.yaml` #### UI Configuration -1. **Open the tools dropdown in the chat input bar** -![Tools configuration button](/images/web-search/tools_highlight.png) +1. **Click + in the [message composer](/docs/features/composer) to open the palette** -2. **Click on the gear icon next to Web Search** -![Tools configuration section](/images/web-search/tools_config_highlight.png) +2. **Choose Configure on the Web Search row in the Tools section** 3. **Select SearXNG from the Search Provider dropdown** ![SearXNG dropdown selection](/images/web-search/searxng_dropdown_highlight.png) @@ -708,11 +706,9 @@ You can configure SearXNG in LibreChat within the UI or through `librechat.yaml` 4. **Enter your configuration details (e.g. instance URL, scraper type, etc.) and click save** ![Save web search configuration](/images/web-search/web_search_save.png) -5. **Click on the Web Search option in the tools dropdown** -![Web search badge in chat interface](/images/web-search/websearch_highlight.png) +5. **Select Web Search in the palette's Tools section** -6. **The Web Search badge should now be enabled, meaning your queries can now utilize the web search functionality** -![Web search badge confirmation](/images/web-search/search_badge_confirm.png) +6. **A Web Search chip now appears on the composer, meaning your queries can now use web search** #### YAML Configuration diff --git a/content/docs/configuration/mod_system.mdx b/content/docs/configuration/mod_system.mdx index 12b53778d..1900944fa 100644 --- a/content/docs/configuration/mod_system.mdx +++ b/content/docs/configuration/mod_system.mdx @@ -59,6 +59,38 @@ The following are all of the related env variables to make use of and configure ]} /> +### Two-factor and passkey rate limiting + + + +The two-factor violation scores are `TWO_FACTOR_TEMP_VIOLATION_SCORE`, which falls back to `LOGIN_VIOLATION_SCORE`, and `TWO_FACTOR_SETUP_VIOLATION_SCORE`, which falls back to `TWO_FACTOR_TEMP_VIOLATION_SCORE` and then `LOGIN_VIOLATION_SCORE`. See [Required Two-Factor Authentication](/docs/configuration/authentication#required-two-factor-authentication) and [Passkeys](/docs/configuration/authentication/passkeys). + +### Email change rate limiting + + + +These can also be set under [`rateLimits.emailChange` and `rateLimits.emailChangeConfirm`](/docs/configuration/librechat_yaml/object_structure/config#ratelimits) in `librechat.yaml`, which take precedence over the environment variables. Exceeding the request limit is scored with `EMAIL_CHANGE_VIOLATION_SCORE` (default `1`). The verification link limits only return HTTP 429: whoever opens the link is not signed in, so there is no account to score. + ### Message rate limiting ` with your Azure app registration's Application (client) ID ### File Selection Process -1. User clicks "From SharePoint" in the attachment menu +1. User selects **From SharePoint** in the **Attach** section of the [composer's **+** palette](/docs/features/composer#add-files) 2. SharePoint Online file picker opens in an embedded iframe 3. User browses and selects files using the familiar SharePoint interface; current selections remain checked while opening other folders or switching picker views 4. Selected files are queued for download @@ -166,10 +166,10 @@ Replace `` with your Azure app registration's Application (client) ID ### Accessing SharePoint Files -When properly configured, users will see a new option in the file attachment menu: +When properly configured, users will see a new option in the **Attach** section of the [composer's **+** palette](/docs/features/composer#add-files): -1. Click the attachment icon in the message input -2. Select "From SharePoint" from the menu +1. Click **+** in the message composer +2. Select **From SharePoint** (with [`legacyFileUploadUX`](/docs/configuration/librechat_yaml/object_structure/file_config#legacyfileuploadux) enabled, choose a destination labeled with **(From SharePoint)** under **More upload options**) 3. The SharePoint file picker will open 4. Browse and select files as needed 5. Click "Select" to begin downloading diff --git a/content/docs/features/admin_panel.mdx b/content/docs/features/admin_panel.mdx index 62fa4f01a..5cbd5ccfa 100644 --- a/content/docs/features/admin_panel.mdx +++ b/content/docs/features/admin_panel.mdx @@ -228,6 +228,28 @@ This is the surface behind LibreChat's [DB-backed per-principal configuration ov Administrators can also use the opt-in [Admin Insights](/docs/features/insights) dashboard to review tenant-scoped MongoDB activity. Set `ENABLE_INSIGHTS=true`, then grant both `access:admin` and `read:insights` to an account with the `ADMIN` role. +### Override Validation + +Override writes (`PUT /api/admin/config/:principalType/:principalId` and `PATCH .../fields`) are validated against the same schema as `librechat.yaml`, applied on top of the deployment's base config. A write that would produce an invalid config is rejected with HTTP 400 and nothing is saved: + +```json +{ + "error": "Invalid config override", + "code": "CONFIG_OVERRIDE_INVALID", + "issues": [{ "path": "interface.fileSearch", "code": "invalid_type" }] +} +``` + +Each issue carries only the dot-path and a stable code (a schema issue code such as `invalid_type`, or `missing_merge_key`, `duplicate_merge_key`, `indexed_merge_key_write`, `union_dropped_key` or `invalid_document`), never the submitted value. A field patch is only rejected for problems it touches or introduces, so an older invalid value elsewhere in the same override does not block it. + +Stored overrides that have become invalid, for example after an upgrade tightens the schema, are not fatal. When the config is resolved, the invalid fields are dropped, the value beneath them (usually the base `librechat.yaml` value) applies, and the server logs one warning per field: + +```text +[mergeConfigOverrides] Ignoring invalid override "" for / () +``` + +Check the logs for these lines after upgrading, then fix or remove the listed fields in the panel. An override theme that fails the [theme rules](/docs/configuration/librechat_yaml/object_structure/theme#validation) falls back to the base theme in the same way. + ### Section-Scoped Delegation Configuration grants can be broad (`read:configs`, `manage:configs`) or limited to one top-level section (`read:configs:
`, `manage:configs:
`). A section-scoped reader receives a filtered configuration response containing only authorized sections instead of being denied the entire request. Section-level manage grants imply read access to the same section; broad manage access implies broad read access. diff --git a/content/docs/features/agents.mdx b/content/docs/features/agents.mdx index 3e7338772..7cb00dea1 100644 --- a/content/docs/features/agents.mdx +++ b/content/docs/features/agents.mdx @@ -23,6 +23,7 @@ The creation form includes: - **Description**: Optional details about your agent's purpose - **Instructions**: System instructions that define your agent's behavior - **Model**: Select from available providers and models +- **Conversation Starters**: Up to four suggested prompts shown when a user starts a new chat with the agent The **Tools** and **Skills** controls open searchable libraries for built-in capabilities, tools, MCP servers, Actions, and Skills. Select an item to configure it, then save the agent. @@ -60,6 +61,21 @@ Recognized model-not-found and provider rate-limit failures render localized gui Users with edit access can open **Version History** from the Agent Builder to inspect saved configurations in a timeline. Each entry shows when it was saved and summarizes its tools and capabilities. Restoring an earlier entry requires confirmation and replaces the current agent configuration with that saved state. Saving always applies the Agent's current changes, even when the resulting configuration matches the newest history entry and LibreChat does not add a duplicate entry. +### Conversation Starters + + + Newer than **v0.8.8**. Available now on LibreChat's `dev` and `canary` branches, and in the next release. + + +Conversation starters give users a quick way to begin a chat with an agent. Each agent can store up to four. + +1. In the Agent Builder, find the **Conversation Starters** field. +2. Type a prompt and press **Enter**, or select the **+** button. The input is disabled once four starters are added. +3. Edit a saved starter in place, or select its **X** button to remove it. +4. Save the agent. + +When a user opens a new chat with the agent, the starters appear as buttons on the empty chat screen. Selecting one sends it immediately as the first message. If the agent has starters, they take precedence over any [`conversation_starters`](/docs/configuration/librechat_yaml/object_structure/model_specs#conversation_starters) defined on the model spec in use. Starters also appear in the agent's [Marketplace](#agent-marketplace) detail dialog. + ## Agent Capabilities > **Note:** All capabilities can be toggled via the `librechat.yaml` configuration file. See [docs/configuration/librechat_yaml/object_structure/agents#capabilities](/docs/configuration/librechat_yaml/object_structure/agents#capabilities) for more information. @@ -212,6 +228,8 @@ Generic Agent and MCP tool cards distinguish **Preparing** (before SDK handoff, While a tool is running, expanded Bash, Execute Code, and File Authoring detail panes follow streamed commands, code, or preview content to the bottom. Scrolling upward pauses that follow behavior so the current reading position is preserved. +Bash output renders as terminal-style text. Long output is collapsed to its last 15 lines, where errors usually appear; use **Show more** and **Show less** to expand or collapse it, and the **Copy** button to copy the output. A command that printed nothing shows **No output**. For commands run in an [attached workspace](/docs/features/code_interpreter#attached-environments-and-pairing), a failed command is marked with its reason (**exit code N**, **terminated by** a signal such as `SIGKILL`, or **timed out**), and stderr is styled separately from stdout. A finished command is labelled **Ran command**, and a tool group that contains a single call opens directly to that call's details. + ### Live Reasoning Labels Live reasoning labels replace a generic **Thinking** or **Thoughts** heading with a short orientation that evolves as sufficiently long top-level reasoning streams. The label updates the existing reasoning heading in place; it does not add or reorder message parts. @@ -304,7 +322,7 @@ By default, an agent uses the user's shared personal memory pool. Turn on **Keep The Artifacts capability enables your agent to generate and display interactive content: - Create React components, HTML code, and Mermaid diagrams -- Display content in a separate UI window for clarity and interaction +- Display content in a dedicated panel beside the chat, which can be expanded to fullscreen or opened in its own browser window - Configure artifact-specific instructions at the agent level - [More info about Artifacts](/docs/features/artifacts) @@ -514,6 +532,24 @@ Conversation surfaces keep the Agent as the visible identity and do not fall bac For full details on principals, permission bits, and how ACLs compose with role-based feature permissions, see [Access Control](/docs/features/access_control). +### Agent Marketplace + +The **Agent Marketplace** lets users browse the agents available to them. Open it from **Agent Marketplace** in the sidebar; the entry appears only for users whose role is allowed to use the Marketplace. + +- **Browse and search**: Agents appear in a grid. Use the search field to find agents by name or description, and the category pills (such as **Top Picks**, **All**, or a specific category) to narrow the list. +- **Sort**: Use **Sort by** to order agents by **Newest first** (the default), **Oldest first**, **Popular** (most pinned), or **By creator name**. +- **My agents**: Turn on **My agents** to show only agents you created. Turning it on from **Top Picks** switches to **All**. +- **Shareable views**: Search, sort, and the **My agents** filter are kept in the page URL (`?q=`, `?sort=`, `?mine=1`), so a filtered view can be bookmarked or shared. + +Select an agent card to open its detail dialog, which shows the full description and the agent's contact, along with these actions: + +- **Pin** or **Unpin**: Add the agent to, or remove it from, your pinned agents. +- **Copy Link**: Copy a link that starts a new chat with the agent. +- **Start Chat**: Open a new conversation with the agent. +- **Try a conversation starter**: When the agent has [conversation starters](#conversation-starters), select one to open a new chat with that prompt already in the message input. It is not sent automatically, so you can edit it first. + +Administrators can control access with the [`interface.marketplace`](/docs/configuration/librechat_yaml/object_structure/interface#marketplace) setting and the role permissions described in [Access Control](/docs/features/access_control). + ### Administrator Controls Administrators have access to global permission settings within the agent builder UI: @@ -547,7 +583,7 @@ Individual users can: ## Steering and Queued Messages -While an Agent is responding, you can send another message in either of two ways: +While an Agent is responding, you can send another message from the [composer](/docs/features/composer) in either of two ways: - **Steer** inserts the message into the current run at its next tool or agent step, so the agent can adjust its work before finishing. - **Queue** holds the message and sends it as a normal follow-up turn after the current response completes. @@ -556,19 +592,19 @@ For saved Agent conversations on a current server, ordinary queued follow-ups ar Server admission is serialized within each conversation queue lane. If predecessor evidence or mixed-version ownership is ambiguous, LibreChat shows **Awaiting reconciliation** and blocks or fails the affected queued turn instead of guessing and starting it out of order. -**Interrupt & steer** preempts the current provider work. If no answer text or tool activity is safe to keep yet, LibreChat waits through a short grace period, discards the silent or reasoning-only attempt, inserts the message, and restarts the model with that instruction. Once answer text can be kept, LibreChat stops at a provider-safe boundary, preserves the partial response, inserts the message, and resumes the same assistant response. A running tool call is not discarded or interrupted by steering; the message applies when that work reaches a safe boundary. +**Steer sooner** asks the agent to take the message at the next safe point instead of waiting for the next tool step. If no answer text or tool activity is safe to keep yet, LibreChat waits through a short grace period, discards the silent or reasoning-only attempt, inserts the message, and restarts the model with that instruction. Once answer text can be kept, LibreChat stops at a provider-safe boundary, preserves the partial response, inserts the message, and resumes the same assistant response. A running tool call is not discarded or interrupted by steering; the message applies when that work reaches a safe boundary. Use **Stop** to end active reasoning and request cancellation of a foreground tool call. Stop forwards cancellation to signal-aware foreground tools; detached background work keeps its independent lifecycle. Use the dedicated composer control, choose it from the send-button menu, or press `Command/Ctrl + Shift + .`. The action falls back to ordinary steering when the deployment cannot interrupt the active provider stream. -Under **Settings → Chat**, **While generating, Enter will** chooses the default action. The send-button menu can override that choice for an individual message, and **Steering interrupts generation** controls whether ordinary steering also requests an interrupt. +Under **Settings → Chat**, **While generating, Enter will** chooses the default action. The send-button menu can override that choice for an individual message, and **Steer sooner on Enter** makes Enter request that earlier safe point when steering is the default. Files and [quoted excerpts](/docs/features/message_actions#quote-excerpts) travel with steer, queue, and interrupt messages. Manually selected Skills remain staged for the next full turn instead of being attached to a mid-run steer. -Pending steers appear above the composer until the server inserts them into the run. Their receipt progresses from **Sending** to **Delivered**, then **Interrupting** when a preempt is armed, and finally **Applied** with a double checkmark at the inline message's bottom-right edge. Confirmed applied receipts remain visible after reload and in share or search views; uncertain or failed delivery never shows a confirming checkmark. Once acknowledged, the message menu can reclaim the steer for editing, convert it into a queued follow-up, or cancel it and restore its text and attachments to the composer. LibreChat avoids overwriting a newer draft; if the composer is no longer available, it preserves the reclaimed message in the queue instead. A failed steer remains available to retry, edit, queue, or remove. +Pending steers appear at the end of the streaming reply, where they will land, until the server inserts them into the run. Their receipt progresses from **Sending** to **Delivered**, then **Steer sooner requested** when an earlier safe point was requested, and finally **Applied** with a double checkmark at the inline message's bottom-right edge. Confirmed applied receipts remain visible after reload and in share or search views; uncertain or failed delivery never shows a confirming checkmark. Once acknowledged, the message menu can reclaim the steer for editing, convert it into a queued follow-up, or cancel it and restore its text and attachments to the composer. LibreChat avoids overwriting a newer draft; if the composer is no longer available, it preserves the reclaimed message in the queue instead. A failed steer remains available to retry, edit, queue, or remove. -Queued follow-ups can be sent immediately, converted into a steer while the run is still active, escalated to **Interrupt & steer now**, edited, or removed. In-flight steers offer the same escalation when they are still waiting for a tool boundary. Removing a server-backed queued message first cancels its durable source, then restores it to an empty composer when possible. If the preceding response is aborted or fails, LibreChat marks the affected queued turn as failed for review instead of silently sending it. +Queued follow-ups appear in a list above the composer. Each one can be edited (**Edit message**), removed (**Remove message**), sent right away with **Send now**, or reordered by dragging its handle or pressing the arrow keys on it. Queued follow-ups can also be converted into a steer while the run is still active or escalated with **Steer sooner**. In-flight steers offer the same escalation when they are still waiting for a tool boundary. Removing a server-backed queued message first cancels its durable source, then restores it to an empty composer when possible. If the preceding response is aborted or fails, LibreChat marks the affected queued turn as failed for review instead of silently sending it. -A conversation can have up to 100 active queued turns. Each queued turn accepts up to 16,000 characters and 10 files. Separately, one active run accepts up to 10 pending steers; each steer can include up to 10 files and is limited by [`STEER_MAX_LENGTH`](/docs/configuration/dotenv#agent-conversation-controls). **Interrupt & steer** continues to use the live steering path rather than moving a queued turn to the front of the durable FIFO lane. +A conversation can have up to 100 active queued turns. Each queued turn accepts up to 16,000 characters and 10 files. Separately, one active run accepts up to 10 pending steers; each steer can include up to 10 files and is limited by [`STEER_MAX_LENGTH`](/docs/configuration/dotenv#agent-conversation-controls). **Steer sooner** continues to use the live steering path rather than moving a queued turn to the front of the durable FIFO lane. Redis-backed multi-replica deployments negotiate generation protocol v2 automatically. Follow the [generation protocol compatibility guidance](/docs/configuration/redis#generation-protocol-compatibility) when upgrading from a release older than `v0.8.8-rc1`. diff --git a/content/docs/features/artifacts.mdx b/content/docs/features/artifacts.mdx index 36591f5b4..f4f9ff89c 100644 --- a/content/docs/features/artifacts.mdx +++ b/content/docs/features/artifacts.mdx @@ -37,6 +37,14 @@ Agent-level configuration is preferred because each agent can use the mode and i Use the fullscreen control in a rendered artifact preview to expand it to the complete browser display. The control follows browser Fullscreen API state, exits normally with Escape or browser controls, and is hidden when fullscreen is unavailable. +On desktop, select **Open in new window** (newer than **v0.8.8**) in the artifact panel header to move the panel into a separate browser window, for example to place it on a second screen. The artifact keeps updating as the response streams, and unsaved code edits and the selected tab carry over. To return the panel to the chat, select **Dock back to panel** or close the window. LibreChat remembers the window's size and position for the next time. + +- Keep the chat tab open: the window is controlled by the chat tab, and closing that tab also closes the window. +- If the browser blocks the window, LibreChat shows a notice. Allow pop-ups for the site and try again. +- The button is not shown on narrow (mobile) layouts. + +Administrators can remove the button and keep artifacts in the side panel by setting [`interface.artifactUndocking: false`](/docs/configuration/librechat_yaml/object_structure/interface#artifactundocking). + Mermaid diagrams appear as compact inline cards that can open in the artifact panel. Export a diagram as SVG or PNG from either the inline card or the panel. Mermaid previews render directly rather than loading the Sandpack bundler; PNG export applies bounded canvas dimensions to protect the browser from oversized diagrams. Model-authored artifacts download under their title or Markdown heading with an extension matching the exported content. An unedited file-backed artifact downloads the complete original with its original filename and format when available. Downloading edited or cached preview content uses a `.preview` qualifier so it is not mistaken for the original file. diff --git a/content/docs/features/authentication.mdx b/content/docs/features/authentication.mdx index f5467e5ff..1fa5edca2 100644 --- a/content/docs/features/authentication.mdx +++ b/content/docs/features/authentication.mdx @@ -20,6 +20,27 @@ Additionally, our system can integrate social logins from various platforms such **See also:** [Access Control](/docs/features/access_control), LibreChat's granular permission system for users, groups, and roles, covering per-resource sharing of agents, prompts, MCP servers, and feature-level permissions. +## Two-Factor Authentication + +Local and LDAP accounts can add a second factor (a one-time code from an authenticator app, plus backup codes) under **Settings > Account > Two-factor authentication**. Accounts that sign in through an identity provider (OAuth, OpenID Connect, SAML) use that provider's MFA instead. + +Administrators can make 2FA mandatory with `ENFORCE_TWO_FACTOR_AUTHENTICATION=true`. Users without 2FA then see a **Two-Factor Authentication Required** screen after signing in and must finish setup before they can use LibreChat. Once enforced, the disable control shows **Required by administrator** and 2FA cannot be turned off. See [Required Two-Factor Authentication](/docs/configuration/authentication#required-two-factor-authentication). + +## Passkeys + +When an administrator enables them, local-account users can sign in with **Sign in with a passkey** instead of a password, using their device screen lock, a password manager, or a security key. Passkeys are added and removed under **Settings > Account > Passkeys**; both actions ask for the account password first. If the account also has 2FA, the code is still requested after a passkey sign-in. See [Passkeys](/docs/configuration/authentication/passkeys) for setup. + +## Changing Your Email Address + +Local-account users can change their registered email under **Settings > Account > Email address** by selecting **Change**. In the **Change email address** dialog, enter the new address and the current password, then select **Send verification link**. + +- The change takes effect only after the link sent to the **new** address is opened. The link is single-use and expires after 15 minutes by default. +- The **current** address receives a security notice as soon as a change is requested. After the change is confirmed, both addresses receive an "email changed" notice. +- The new address must not belong to another account and must be in the deployment's allowed registration domains, if any are set. +- Changing your password before opening the link makes the link invalid; request a new one. + +The option appears only when the server can send email and the feature is enabled. See [Email address change](/docs/configuration/authentication/email#email-address-change). + ## 2FA Management Attempt Limits Two-factor authentication settings share an account-level attempt budget: **7 requests per 5 minutes** by default, across enabling, verifying, confirming, disabling, and regenerating backup codes. Successful requests consume attempts too. Opening a new session does not create another budget for the same tenant and account. diff --git a/content/docs/features/code_interpreter.mdx b/content/docs/features/code_interpreter.mdx index 3d6b21f04..ac55ec18b 100644 --- a/content/docs/features/code_interpreter.mdx +++ b/content/docs/features/code_interpreter.mdx @@ -123,6 +123,8 @@ Personal environments are bound to the authenticated user and tenant, protected Agents using an attached workspace can list its directory tree, read files, search file contents, create or edit files, and run Bash on the selected worker. File citations use workspace-relative paths, authored files appear in the response's **Workspace changes** row, and tool failures preserve the worker's bounded HTTP diagnostics. An Agent can also store a per-Agent Git name and email for commits created in that workspace; these values configure authorship only and do not provide repository credentials. +In the chat, a failed attached-workspace Bash command shows its exit code, terminating signal, or timeout, and its stderr is styled separately from stdout. See [Activity Groups](/docs/features/agents#activity-groups) for how Bash output is displayed. + An attached worker advertises the workspace roots it makes available. The composer lets the user select one workspace for each attached environment reachable through the Agent or its Subagents; a single unambiguous workspace is selected automatically for a new conversation. LibreChat stores these selections on the conversation, revalidates them against the live worker before execution, and keeps them fixed through approval pauses and resumed runs. Sending is blocked when a required selection is missing or unavailable, and LibreChat never silently substitutes another workspace. At the start of a run, LibreChat can load repository instructions from the selected workspace so the Agent follows that repository's guidance; administrators can bound discovery with [`repositoryInstructions.timeoutMs`](/docs/configuration/librechat_yaml/object_structure/agents#repositoryinstructions). Native file and Bash workspace tools can use an advertised root even when the worker does not support reusable runtime sessions. Workspace-aware Programmatic Bash is available on compatible Code API and worker builds when the Agent's programmatic-tool configuration permits it, the authorized attached worker is ready and advertises `programmaticLanguages: ['bash']`, and both the selected workspace and worker allow `execute_command`. LibreChat passes the server-validated workspace ID and conversation workspace-instance ID, when present, to the programmatic tool; model arguments cannot replace that selection. Without these capabilities, Programmatic Bash is disabled; use direct Bash for workspace-aware commands. When the worker supports file relay, chat uploads are staged separately under `$LIBRECHAT_CODE_DATA_DIR` for the programmatic run, not copied into the selected workspace. **Stop** cancels a signal-aware in-flight BYOM command without invalidating the workspace for later commands; detached work retains its separate cancellation lifecycle. For an attached execution environment, the Agent Builder can set a **Workspace default** to one currently advertised root. It is validated against that attached environment and used to initialize new conversations for that Agent. Choose **Last used** to use the signed-in user's browser-local preference for that Agent and environment; it is only a convenience hint, never an authorization grant or conversation binding. Changing the execution environment clears an explicit default, and a saved root that is no longer advertised remains visible but cannot be selected until it is reconfigured. diff --git a/content/docs/features/composer.mdx b/content/docs/features/composer.mdx new file mode 100644 index 000000000..152df01dc --- /dev/null +++ b/content/docs/features/composer.mdx @@ -0,0 +1,141 @@ +--- +title: Message Composer +icon: MessageSquare +description: Write messages, attach files, and turn on tools, skills and MCP servers from the composer's + palette, then queue or steer follow-ups while a response streams. +--- + +The message composer is the box at the bottom of every chat. Besides the text field, it holds one **+** button that opens everything you can add to a message (files, tools, skills, MCP servers and files you uploaded before), the chips for the tools that are currently on, and the controls for reasoning, dictation and sending. + + + The composer described on this page is newer than **v0.8.8**. Earlier releases use a toolbar with separate attach and MCP Servers dropdowns. The redesign is available on LibreChat's `dev` and `canary` branches and ships in the next release. + + +## What's on the composer + +| Element | What it does | +|---|---| +| **+** (**Attach and tools**) | Opens the palette: upload options, tools, skills, MCP servers and your recent files, all searchable from one field. | +| Tool chips | One chip per tool or MCP server that is on, next to the **+** button. Remove a chip to turn that tool off. | +| Staged context | Files, quotes and skills attached to your next message, shown above the text field. | +| **Thinking** | Reasoning effort for models that support it. | +| Context usage | How much of the model's context window the conversation uses, when token usage is available. | +| **Use microphone** | Dictates your message with speech to text, when speech to text is enabled. | +| Send / Stop | Sends the message, or stops the response that is streaming. | + +To see which keys apply right now, such as `/ for prompts`, `@ for models` or `Enter to send`, turn on **Show composer tips** in **Settings > General**. A one-line tip then appears under the text field. It is off by default. + +## Add files + +Click **+** and choose an option in the **Attach** section. You can also drag files onto the composer or paste them. + +By default, LibreChat uses the unified uploader: you pick only a source, and it decides how each file reaches the model (native provider upload, text extraction, or a tool such as File Search) from the file type and the endpoint. + +| Option | When it appears | +|---|---| +| **From Local Computer** | Always, with the default uploader. | +| **From SharePoint** | When the [SharePoint file picker](/docs/configuration/sharepoint) is enabled. | + +If an administrator sets [`fileConfig.legacyFileUploadUX: true`](/docs/configuration/librechat_yaml/object_structure/file_config#legacyfileuploadux), you choose the destination yourself instead. The **Attach** section then shows the main option first and folds the rest behind **More upload options**: + +| Option | When it appears | +|---|---| +| **Upload to Provider** | The provider accepts documents directly (for example OpenAI, Anthropic, Google, Bedrock, OpenRouter and custom endpoints, or Azure OpenAI with the Responses API on). | +| **Upload Image** | Shown instead of **Upload to Provider** when the provider only accepts images. | +| **Upload as Text** | The [context capability](/docs/features/upload_as_text) is enabled. | +| **Upload for File Search** | File Search is enabled and allowed for the current agent. Picking it also turns File Search on. | +| **Upload to Code Environment** | Code execution is enabled and allowed for the current agent. Picking it also turns **Run Code** on. | +| **Attach Files** | Assistants endpoints, which handle files with the assistant's own configuration. | + +With SharePoint enabled in this mode, each option also has a SharePoint version, labeled for example **Upload to Provider (From SharePoint)**. + +### Reuse a file you uploaded before + +The **Your files** section of the palette lists your most recently used files. Select one to attach it again without uploading it. Typing in the search field searches all of your files by name. + +Choose **Show all** on the section to browse every file in a dialog, with **All**, **Images** and **Documents** views, a search field, and a preview for images and PDFs. + +The palette shows up to five recent files. Administrators can lower that number, or hide the list with `0`, using [`interface.composerRecentFiles`](/docs/configuration/librechat_yaml/object_structure/interface#composerrecentfiles). + +## Turn on tools, skills and MCP servers + +The palette lists everything you can turn on for the current conversation, grouped into sections: + +- **Tools**: built-in tools such as **Web Search**, **Run Code**, **File Search**, **Skills**, **Memory** and **Artifacts**, each shown only when it is enabled and you have access to it. +- **Skills**: individual [skills](/docs/features/skills) you can attach to your next message. +- **MCP Servers**: the [MCP servers](/docs/features/mcp) available in chat. + +Select a tool or MCP server to switch it on or off. The palette stays open, so you can switch several in one visit. Each tool that is on appears as a chip on the composer; remove the chip to switch it off. Some chips carry a mode menu, for example the **Artifacts** generation mode. + +Selecting a skill stages it for your next message instead: it appears in the [staged context](#staged-context) rather than as a chip. + +MCP server rows show each server's connection status. Selecting a server that is not connected starts its connection (including an OAuth sign-in, when the server needs one) or opens its configuration first if it needs your credentials. Once connected, servers that take user credentials also have a **Configure** control on the row, and **Web Search** has one for its API keys. + + + With an agent selected, the **Tools** and **MCP Servers** sections are hidden, because the agent's own configuration decides which tools it uses. On other endpoints, a [model spec](/docs/configuration/librechat_yaml/object_structure/model_specs#hidebadgerow) with `hideBadgeRow: true` hides the **Tools**, **Skills** and **MCP Servers** sections. **Attach** and **Your files** stay available in every case. + + +### Show all + +The palette shows a handful of rows per section. Choose **Show all** on the **Skills**, **MCP Servers** or **Your files** header to open a dialog with the full list, a search field and filters. Skills and MCP servers have three views: **All**, **Made by you** and **Favorites**. + +### Favorites and pinned tools + +Star a row to add it to **Favorites**, which sits at the top of the palette. With a row highlighted, press Ctrl+D (Cmd+D on macOS) to star or unstar it. Favorites are saved to your account. + +Administrators can pin built-in tools with [`interface.defaultPinnedTools`](/docs/configuration/librechat_yaml/object_structure/interface#defaultpinnedtools). A pinned tool keeps its chip on the composer even while it is off, so you can switch it on with one click. Removing the chip of a pinned tool that is off unpins it. + +## Staged context + +Everything attached to your next message appears above the text field before you send it: + +- **Files**, with upload progress and a preview for images. Long pasted text can also land here as a file, which you can edit or move back into the message. +- **Quotes** you selected from earlier messages. +- **Skills** you picked from the palette or with the `$` command. + +Remove any item with its remove button. Everything staged is sent with your next message. + +## Thinking and effort + +For models with a reasoning setting, the **Thinking** control opens a slider that runs from **Faster** to **Smarter**, plus the provider's separate modes such as **Auto** or off. It changes the same parameter as the Parameters panel, so it is hidden when the model has no reasoning setting or when the deployment turns parameters off with `interface.parameters`. + +## Queue and steer while a response streams + +You can keep typing while a response is streaming. Depending on the endpoint and your settings, pressing Enter either queues the message to send after the response, or steers an agent's current response. The composer tip names the action that Enter performs at that moment. + +Queued messages appear in a **Queued messages** rail above the composer, where you can: + +- **Edit message** to move it back into the text field. +- **Remove message** to take it out of the queue. +- **Send now** to send it right away instead of waiting. +- Reorder messages by dragging them, or by focusing one and pressing the up and down arrow keys. + +For how steering works and when it is available, see [Steering and Queued Messages](/docs/features/agents#steering-and-queued-messages). + +## Keyboard shortcuts + +### In the text field + +| Keys | Action | +|---|---| +| Enter | Send the message (queue or steer while a response streams). | +| Shift+Enter | New line. | +| Ctrl+Enter (Cmd+Enter) | While a response streams: the alternate action, **send now** when Enter queues, or **queue** when Enter steers. | +| Alt+Enter (Option+Enter) | While an agent responds: interrupt and send, when available. | +| Ctrl+Shift+X (Cmd+Shift+X) | Stop the response. | +| `/` | Insert a saved prompt. | +| `@` | Switch to another model, preset or agent. | +| `+` | Add a model or preset for an additional response. | +| `$` | Pick a skill for the next message. | + +If you turned off **Press Enter to send messages**, Ctrl+Enter (Cmd+Enter) sends and Enter adds a new line. + +### In the palette + +| Keys | Action | +|---|---| +| Type | Search tools, skills, servers, upload options and files. | +| ↑ / ↓ | Move through the rows. | +| Enter | Select the highlighted row. | +| Ctrl+D (Cmd+D) | Add the highlighted row to Favorites, or remove it. | +| Backspace on an empty search | Close the palette. | +| Escape | Close the palette. | diff --git a/content/docs/features/mcp.mdx b/content/docs/features/mcp.mdx index 90c8019e4..f7beb0aa0 100644 --- a/content/docs/features/mcp.mdx +++ b/content/docs/features/mcp.mdx @@ -42,7 +42,7 @@ Register this exact callback URL with the OAuth provider. Local Docker installs LibreChat displays configured MCP servers directly in the chat area when using traditional endpoints (OpenAI, Anthropic, Google, Bedrock, etc.): - Select any non-agent endpoint first, and a tool-compatible model -- MCP servers appear in a dropdown in the chat interface below your text input +- MCP servers appear in the **MCP Servers** section of the [composer's **+** palette](/docs/features/composer#turn-on-tools-skills-and-mcp-servers), and each selected server shows as a chip on the composer - When selected, all tools from that server become available to your current model - Quick access to MCP tools without creating an agent, allowing multiple servers to be used at once @@ -131,7 +131,7 @@ Your new server will appear in the MCP Settings panel with a confirmation toast. #### Step 3: Check Connection Status and Authenticate -Review the [connection status indicator](#connection-status-indicators) for your new server. If the server requires OAuth authentication, the status will show as disconnected. Click the server's authenticate/connect button (you can do this either by clicking on the MCP server itself in the chat dropdown menu, or by clicking on the connection icon first to be taken to a dialog with more information on the connection state) to begin the authentication flow. +Review the [connection status indicator](#connection-status-indicators) for your new server. If the server requires OAuth authentication, the status will show as disconnected. Select the MCP server in the composer's **+** palette to begin the authentication flow. ![Connection Status - Disconnected](/images/mcp/mcp_ui_unconnected.png) @@ -155,7 +155,7 @@ After authenticating, you'll see a success confirmation. This window will automa #### Step 6: Server Ready for Use -LibreChat acknowledges the successful authentication and automatically selects the MCP server for use within your conversation. The server now shows a connected status indicator and is checked in the MCP Servers dropdown. +LibreChat acknowledges the successful authentication and automatically selects the MCP server for use within your conversation. The server now shows a connected status indicator and appears as a selected chip on the composer. ![MCP Server Authenticated and Auto-Selected](/images/mcp/mcp_ui_done.png) @@ -226,7 +226,7 @@ LibreChat provides comprehensive tools for managing MCP server connections with ### Connection Status Indicators -LibreChat displays dynamic status icons showing the current state of each MCP server in the chat dropdown and settings panel: +LibreChat displays dynamic status icons showing the current state of each MCP server in the composer's **+** palette and the settings panel: ![MCP Server Status Icons](/images/mcp/mcp_server_status_icons.png) @@ -249,13 +249,13 @@ You can initialize or re-initialize MCP servers directly from the interface: **One click:** -- One-click initialization from the MCP server selection dropdown +- One-click initialization by selecting the server in the **MCP Servers** section of the composer's **+** palette