Skip to content

🧾 feat: Write Reports, Profile Priority, Pre-Auth Sign-In and Per-Field Titles from the Config Contract - #174

Open
danny-avila wants to merge 3 commits into
pr/config-meta-gatingfrom
pr/config-backend-feature-ui
Open

danny-avila wants to merge 3 commits into
pr/config-meta-gatingfrom
pr/config-backend-feature-ui

Conversation

@danny-avila

@danny-avila danny-avila commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Pull Request Template

⚠️ Before Submitting a PR, Please Review:

  • Please ensure that you have thoroughly read and understood the Contributing Docs before submitting your Pull Request.

⚠️ Documentation Updates Notice:

  • Kindly note that documentation updates are managed in this repository: librechat.ai

Summary

Builds on the admin config contract (GET /api/admin/config/meta) from the previous PR. Newer LibreChat servers now report what they do on writes, how profiles are ordered, which settings apply before sign-in and how endpoints.all title settings resolve. This PR uses each of those behaviours where the server reports it. A server that does not report a flag (or has no meta route) keeps today's behaviour, and every change below was checked against both kinds of server.

Write rules from the server (rules.baseOnlySections, baseOnlyPaths, deploymentOnlyPaths)

  • The read-only sections, the librechat.yaml-only fields and the startup-only fields now come from one set of write rules, built from the server's contract. The bundled lists are the fallback.
  • These rules drive the read-only section cards, the "managed in librechat.yaml" and "read at startup" notices, the save planner and pre-flight, the YAML import, the "edit in Base" cards in profiles, and the profile merge preview.
  • In a profile's merge preview, the base-only and deployment-only fields keep Base's value even when the profile already stores an override or a hidden setting there, or at a parent of the field. LibreChat ignores those, so the preview no longer shows a stale value.
  • A server that publishes its deployment-only paths makes, for example, the tool filters (filteredTools, includedTools) and skillDeletion read-only. The base-only pull request fields (endpoints.agents.pullRequests.provider, …) are shown read-only on any server that lists them. A field the server no longer lists becomes editable.
  • Turnstile stays read-only on every server.

Write reports (writeReport, secretRebinding) and error codes

  • PATCH, tombstone and field-delete replies are read for skipped and ignored, and each item is shown in the save toast with the panel's wording: base-only, read from librechat.yaml only, a role permission, a dedicated section, a local-process MCP server, or a credential LibreChat won't send.
  • A location the save wrote as a whole counts as not applied. A skipped part of a written value is reported without lowering the applied count. The same goes for an import: a dropped credential inside an imported endpoint is listed in the notice, but the endpoint still counts as imported. A part reported again by a later PATCH of the same save is listed once.
  • When the server reports what it dropped, the reply's report replaces the old guess (a missing section in the stored document). A read-back finding at a path the server already reported is not listed twice.
  • On a server that drops credentials whose destination changed (secretRebinding), a profile that changes an inherited endpoint's base URL now gets "API key: not sent: where it goes changed without the credential being entered again". A reply's ignored describes the whole stored document, so a dropped credential is only shown when the save changed what it belongs to: its custom endpoint, its MCP server, the Azure groups, or the object that holds it (OCR, a speech provider). A later save of another setting, even another endpoint's, does not repeat it.
  • Error replies with a stable code are worded by the panel: a missing principal, a profile that no longer exists, a version conflict, a section the admin may not manage, an invalid priority, a local-process MCP server, a key the database can't store, or an ended session. Other errors keep the server's text.

Structured issues (issueParams, dottedKeys)

  • Validation issues are located by their segments, so a dotted record key (a Bedrock inference profile, a dotted header) stays one key. The issue shows on its record or entry, and an entry is still named by its identity.
  • With issueParams, an issue is worded with its bounds, options and expected type, as the panel words its own checks. For example "must be at least 1" instead of "is too small", "must be at least 20 characters", "must be one of …", "must be a whole number". allowedAddresses refinements are worded by their reason (missing port, public IP, …).
  • Without params, issues stay worded without them, as before.

Web search keys (webSearchStoredKeys)

  • On a server that keeps the Keenable key in its secret registry, a typed or stored Keenable key is treated like the other web search keys: masked, "Will be stored encrypted", shown as a stored preview. Before that it stays plaintext.

Profile order and priority (deterministicPrecedence, priorityRoute, expectedRevision, principalCheck)

  • With deterministic precedence, two active profiles at the same priority no longer get the "which value applies is not defined" warning. The profile bar says which one wins for users in both. On equal priority roles apply before groups and groups before users, and profiles of the same kind apply in creation order. The selector drops the tie warning icon.
  • The precedence help says Base applies first, whatever its priority. The profile index orders ties the same way.
  • Admins with broad manage:configs can change a profile's priority from the profile bar ("Change"), on a server with the priority-only route. Only the priority changes: the profile's overrides, hidden settings and active state stay as stored. A value that is not a whole number from 0 to 1,000,000 is refused inline. A refused change is reported and the field stays open.
  • Creating a profile is one create-only PUT (expectedRevision: 'absent'), without reading it first:
    • When someone created the profile meanwhile (409), the panel opens that profile instead of replacing it.
    • On a server with the principal check, the role is not looked up first. A role, group or user that no longer exists (404 PRINCIPAL_NOT_FOUND) is reported, e.g. There is no role named "X".
    • Older servers keep the read-then-PUT path and the role lookup.

Pre-auth settings in Base (preAuthBaseOverrides)

  • On a server that applies Base overrides before sign-in, the social sign-in buttons are editable in Base. The admin adds options from the known providers and removes them as chips, in the order the sign-in page shows them. Choosing librechat.yaml's list again removes the override.
  • Allowed domains then note that social, SSO and LDAP sign-ins and password resets check the list too, instead of saying they also need to pass the librechat.yaml list.
  • Imports into Base keep the buttons instead of leaving them out.
  • Profiles still show registration as "applies to everyone, edit in Base". Older servers keep the read-only list with the stale-override note.

Global title settings per field (rules.titleResolution: 'field')

  • On a server that resolves endpoints.all title settings per field:
    • A provider's or custom endpoint's title setting is marked "Overridden by Global" only where Global sets that setting.
    • The title endpoint and model are one choice: when Global sets either, the other is marked too. Its explanation names the half Global sets, and "Go to Global" opens that field.
    • The review warns the same way.
    • The Global titles banner, the "ignored while Global exists" summaries and the block wording of the Global card are not shown.
  • The same server folds endpoint references (Ollama is ollama):
    • Endpoint choices show a custom endpoint as written, without "(ollama)".
    • "Added endpoints" no longer says an Ollama reference never matches, and shows it as the configured endpoint.
  • Servers that resolve titles as one block keep the banner, the block shadowing and the served-name hints.

Not in this PR: moving saves to POST …/changes with revisions (the next PR), and the ignored list a profile read returns.

Change Type

  • New feature (non-breaking change which adds functionality)

Testing

Unit and component tests, with the bundled contract and with a server contract:

  • Write rules: the bundled rules equal the panel's previous lists. Server lists make sections, fields and startup-only fields read-only or editable. Pre-auth frees the social sign-in buttons. Rules are built once per contract. The meta route's deployment-only paths are parsed (an unknown reason reads as an operator boundary).
  • Schema coverage under a server contract: every leaf of the Features, Files and System tabs still renders, the tool filters are read-only with LibreChat's deployment-only list, and the social sign-in buttons are edited and saved in Base with pre-auth overrides.
  • Save path:
    • A write report's whole and partial skips, and a PATCH the server skipped entirely.
    • A tombstone the server skipped.
    • Dropped credentials, shown only with secretRebinding and only for what the save changed: the custom endpoint or MCP server entry, a field beside the credential (OCR's base URL), the Azure groups, or a whole section. Another endpoint's setting, or another endpoint in the same list, does not show them. The plan names its changes by entry.
    • A dropped credential is listed apart from the skipped changes, and once across PATCH batches. An import counts only whole skips against its entries.
    • Issues by segments: a dotted record key, and an entry named by its identity.
    • Issues worded by params only with issueParams, and coded errors.
    • Older servers ignore the report.
  • Issue wording: bounds by type and inclusiveness, expected types, literals, options, string checks, multiples and refinement reasons. Error code wording.
  • Profiles: the precedence order and which tie wins. The profile bar's tie notes and priority editor (invalid input, saving, a refused change, Escape). The selector without the tie warning. Create-only creation (one PUT, a 409 opening the existing profile, PRINCIPAL_NOT_FOUND, the role lookup without the principal check). The priority route and its error wording.
  • Registration: editable social sign-in in Base with the pre-auth flag, the matching-librechat.yaml revert, and the read-only list without it.
  • Web search: the Keenable key with stored keys.
  • Titles: per-field and paired shadowing in field states, the review and the providers tab, and endpoint choices and added endpoints with folded names. A paired field names and links to the half Global sets.
  • Profile merge: base-only and deployment-only fields keep Base's value under a profile's override, under a hidden setting, or under a hidden parent.

Live, with Playwright and MongoDB checks, against three LibreChat backends:

  1. Current dev (every flag above except the write report and issue params):
    • Social sign-in: added Apple and removed Google in Base and saved. The signed-out GET /api/config served openid, apple. A YAML import of registration.socialLogins was written to Base.
    • Creating profiles: created a group and a role profile from the selector, at the default priorities.
    • Ties: with both profiles at priority 10 and the same setting, each bar said which one wins.
    • Priority: changing the group's priority refused -3 and an empty value inline, then saved 10. MongoDB kept the overrides and active state.
    • Credentials: changing Moonshot's base URL in a role profile saved with "API key: not sent: …" in the toast. Saving OpenAI's title model in that profile afterwards said "Changes saved". Changing GPT's base URL listed only GPT's API key, not Moonshot's again. Changing OCR's base URL listed OCR's API key.
    • Titles: no Global titles banner. Setting Global's title endpoint marked OpenAI's title model (not its title method) "Overridden by Global". The explanation named Global's title endpoint, and "Go to Global" focused that field. The review warned on an edited title model.
    • Import: importing a new GPT base URL into a role profile said "Imported 1 value into Role: EDITORS", with the dropped API key in the notice.
    • Profile merge: a stale profile override of endpoints.anthropic.vertex, inserted in MongoDB, read as "Vertex AI is not configured" in that profile.
    • Light and dark mode were checked for the new rows and notes.
  2. dev with the open write report change (🧾 feat: Admin Config Write Report, Structured Issues and Deployment-Only Paths LibreChat#17395):
    • The tool filter sections became read-only from the server's rules.
    • A plain Base save reported "Changes saved", with no false warning from the report.
    • Importing a title for a librechat.yaml stdio MCP server was refused with the worded PROCESS_MCP_SERVER_OVERRIDE message.
    • Creating a profile for a role deleted after the list loaded said There is no role named "TEMPROLE".
    • Creating one for a role whose profile was inserted meanwhile opened that profile with its priority and override intact.
  3. An older LibreChat without the meta route:
    • Social sign-in stayed read-only with the stale-override note.
    • The same tie showed the "not defined" warning, with no Change button.
    • The Global titles banner and block shadowing were shown.
    • A role profile was created through the read-then-PUT path.

Test Configuration:

  • LibreChat dev, dev plus the write report change, and an older LibreChat without GET /api/admin/config/meta.
  • MongoDB 8.2 replica set, production-like librechat.yaml.
  • npx tsc --noEmit, npx eslint src/ e2e/, npx prettier --check on the changed files, bun run test:lint-rules, npx vitest run (2646 tests).

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • I have commented in any complex areas of my code
  • My changes do not introduce new warnings
  • I have written tests demonstrating that my changes are effective or that my feature works
  • Local unit tests pass with my changes

…ld Titles from the Config Contract

Shows what a save skipped or ignored and why, maps issues by segments and params, edits profile
priority and creates profiles create-only, makes the pre-auth Base fields editable, and resolves
titles per field — each gated on the server contract with today's behaviour as the fallback.
@danny-avila

Copy link
Copy Markdown
Contributor Author

@codex review

Pass 1. Head: 696595c

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T19:05:16.149153Z 3e0743e Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 696595c7cf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/values.ts Outdated
Comment thread src/utils/layers.ts
Comment thread src/server/config/save.ts Outdated
…aths in Profile Merges, Count Partial Reports Apart
@danny-avila

Copy link
Copy Markdown
Contributor Author

@codex review

Pass 2. Head: 3e0743e

@danny-avila

Copy link
Copy Markdown
Contributor Author

@codex review

Pass 2. Head: 3e0743e

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: 3e0743ef3a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant