From 09f214e14e9a47d9d46a8ee6c5a924712682b601 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 16 Jun 2026 12:39:10 -0700 Subject: [PATCH 1/9] chore: bump librechat-data-provider 0.8.505, @librechat/data-schemas 0.0.53 Bumps the data-provider and data-schemas patch versions to pick up the upstream changes merged since 0.8.503 / 0.0.52. Notable user-visible additions surfaced automatically by the schema-driven UI: modelSpecs conversation_starters (upstream #13710), interface.retainAgentFiles, interface.sharedLinks, interface.mcpServers.configureObo, baseEndpoint titleTiming, agentsEndpoint skills.maxCatalogSkills, custom endpoint reasoningFormat/reasoningKey. Three follow-on type fixes were needed to consume the new versions: role.ts adds a PERMISSION_TYPE_SCHEMA entry for the new PermissionTypes.SHARED_LINKS enum value (upstream #13051). CapabilityPanel.tsx casts cap to BaseSystemCapability in the implication lookup since the union tightened past plain string. server/config.ts drops the AppService call in parseImportedYaml (it was returning an AppConfig wrapper while the consumer ImportYamlDialog expects the flat config) and widens the appConfig return to Record. The widening also sidesteps a type-identity collision introduced by the data-schemas tsdown migration (upstream #13578), which ships dual .d.cts/.d.mts declaration bundles that get nominally distinct under moduleResolution: bundler. --- bun.lock | 8 +++--- package.json | 4 +-- src/components/grants/CapabilityPanel.tsx | 2 +- src/constants/role.ts | 5 ++++ src/server/config.ts | 34 +++++++++++------------ 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/bun.lock b/bun.lock index 5cb0e1e..1f29249 100644 --- a/bun.lock +++ b/bun.lock @@ -6,7 +6,7 @@ "name": "tanstack-start-app", "dependencies": { "@clickhouse/click-ui": "0.2.0-rc.4", - "@librechat/data-schemas": "^0.0.51", + "@librechat/data-schemas": "^0.0.53", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-devtools": "0.10.0", "@tanstack/react-query": "5.95.2", @@ -25,7 +25,7 @@ "i18next-browser-languagedetector": "^8.2.1", "input-otp": "^1.4.2", "js-yaml": "^4.1.1", - "librechat-data-provider": "^0.8.502", + "librechat-data-provider": "^0.8.505", "lucide-react": "^0.545.0", "prom-client": "^15.1.3", "react": "^19.2.0", @@ -292,7 +292,7 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "3.1.2", "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@librechat/data-schemas": ["@librechat/data-schemas@0.0.51", "", { "peerDependencies": { "jsonwebtoken": "^9.0.2", "klona": "^2.0.6", "librechat-data-provider": "*", "lodash": "^4.17.23", "meilisearch": "^0.38.0", "mongoose": "^8.23.1", "nanoid": "^3.3.7", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" } }, "sha512-EBfuq2NitbxgnoJZMXvH8FARvDkte8vNTfE+QDqpnktbM0ftvRqh6wxXQcq2JL50ED8ApuSewoni6gLVCVBwkw=="], + "@librechat/data-schemas": ["@librechat/data-schemas@0.0.53", "", { "peerDependencies": { "jsonwebtoken": "^9.0.2", "klona": "^2.0.6", "librechat-data-provider": "*", "lodash": "^4.17.23", "meilisearch": "^0.38.0", "mongoose": "^8.23.1", "nanoid": "^3.3.7", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" } }, "sha512-R3wcxa4wEd6xzlrh4WuJlMaN9G2hnrUTcRccHOnOnAJUjzhZwFS44+0GOT1/ReQD+SQVeRtQzU/IXuD5u8gRzg=="], "@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.6", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-y+x3H1xBZd38n10NZF/rEBlvDOOMQ6LKUTHqr8R9VkJ+mmQOYtJFxIlkkK8fZrtOiL6VixbOBWMbZGBdal3Z1g=="], @@ -1188,7 +1188,7 @@ "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], - "librechat-data-provider": ["librechat-data-provider@0.8.502", "", { "dependencies": { "axios": "^1.16.0", "dayjs": "^1.11.13", "js-yaml": "^4.1.1", "zod": "^3.22.4" }, "peerDependencies": { "@tanstack/react-query": "^4.28.0" } }, "sha512-t88K1SNZ/o/uSK/MyuMfxhLp4FJsf2shxpa855Lbu0jvtiM4HQ0Mau7GJfuJUzZff9ycOirVTc1xiKmyMl7HPA=="], + "librechat-data-provider": ["librechat-data-provider@0.8.505", "", { "dependencies": { "axios": "^1.16.0", "dayjs": "^1.11.13", "js-yaml": "^4.1.1", "zod": "^3.22.4" }, "peerDependencies": { "@tanstack/react-query": "^4.28.0" } }, "sha512-Bcy7i7H1YR5lGNd44s6Rwf6+ceCUY0npJkDjwdOyUWW63DMRzSEHPWkNAofAyPns4TLXfrCTmSKFGddD7mDkMw=="], "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], diff --git a/package.json b/package.json index a15c01d..4265814 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ }, "dependencies": { "@clickhouse/click-ui": "0.2.0-rc.4", - "@librechat/data-schemas": "^0.0.51", + "@librechat/data-schemas": "^0.0.53", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-devtools": "0.10.0", "@tanstack/react-query": "5.95.2", @@ -41,7 +41,7 @@ "i18next-browser-languagedetector": "^8.2.1", "input-otp": "^1.4.2", "js-yaml": "^4.1.1", - "librechat-data-provider": "^0.8.502", + "librechat-data-provider": "^0.8.505", "lucide-react": "^0.545.0", "prom-client": "^15.1.3", "react": "^19.2.0", diff --git a/src/components/grants/CapabilityPanel.tsx b/src/components/grants/CapabilityPanel.tsx index 77459cd..6da86c4 100644 --- a/src/components/grants/CapabilityPanel.tsx +++ b/src/components/grants/CapabilityPanel.tsx @@ -155,7 +155,7 @@ export function CapabilityPanel({ capabilities, onChange, disabled }: t.Capabili v && ( CapabilityImplications[k as BaseSystemCapability] ?? [] - ).includes(cap), + ).includes(cap as BaseSystemCapability), )?.[0] ?.replace(/:/g, '_') ?? cap.replace(/:/g, '_') }`, diff --git a/src/constants/role.ts b/src/constants/role.ts index 6ce305b..fa7cd81 100644 --- a/src/constants/role.ts +++ b/src/constants/role.ts @@ -53,6 +53,11 @@ export const PERMISSION_TYPE_SCHEMA: Record = { Permissions.SHARE, Permissions.SHARE_PUBLIC, ], + [PermissionTypes.SHARED_LINKS]: [ + Permissions.CREATE, + Permissions.SHARE, + Permissions.SHARE_PUBLIC, + ], }; export function defaultPermissions(): t.RolePermissions { diff --git a/src/server/config.ts b/src/server/config.ts index 274ce12..b46abc4 100644 --- a/src/server/config.ts +++ b/src/server/config.ts @@ -1,7 +1,6 @@ import { z } from 'zod'; import yaml from 'js-yaml'; import { queryOptions } from '@tanstack/react-query'; -import { AppService } from '@librechat/data-schemas'; import { configSchema } from 'librechat-data-provider'; import { createServerFn } from '@tanstack/react-start'; import { SystemCapabilities } from '@librechat/data-schemas/capabilities'; @@ -652,22 +651,23 @@ export const parseImportedYaml = createServerFn({ method: 'POST' }) }; } - try { - const appConfig = await AppService({ config: result.data }); - return { success: true, error: undefined, validationErrors: undefined, appConfig }; - } catch (appServiceError) { - console.warn( - 'AppService failed for imported config, falling back to raw config:', - appServiceError instanceof Error ? appServiceError.message : appServiceError, - ); - const fallbackConfig = result.data; - return { - success: true, - error: undefined, - validationErrors: undefined, - appConfig: fallbackConfig, - }; - } + /** + * `librechat-data-provider` and `@librechat/data-schemas` both migrated + * to tsdown (upstream #13578, #13597) and now ship dual `.d.cts` + `.d.mts` + * declaration files. Under `moduleResolution: bundler`, TS treats + * `TCustomConfig` resolved through one declaration path as nominally + * distinct from `TCustomConfig` resolved through the other, even when + * structurally identical. That collision shows up here as "Two different + * types with this name exist, but they are unrelated" in the ServerFn + * registration. The consumer (ImportYamlDialog) treats appConfig as + * `Record`, so widening the return is the local fix. + */ + return { + success: true, + error: undefined, + validationErrors: undefined, + appConfig: result.data as Record, + }; }); function getFieldDefault(schema: t.ZodSchemaLike): { hasDefault: boolean; value: unknown } { From c1f0bfb0dc686120d2809d4f8efcb68acff4179f Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 16 Jun 2026 14:33:48 -0700 Subject: [PATCH 2/9] =?UTF-8?q?=F0=9F=8C=90=20chore:=20Localize=20new=20co?= =?UTF-8?q?nfig=20fields=20and=20sections=20from=200.8.505=20/=200.0.53=20?= =?UTF-8?q?bump?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The librechat-data-provider 0.8.505 and @librechat/data-schemas 0.0.53 bump in 09f214e surfaced new schema fields that rendered as raw com_config_field_* keys in the admin panel UI. Added English labels for every new field flagged by the localization-coverage test, plus singular array-item labels where needed. Labels follow the existing terse sentence-case style (e.g. softDefault becomes "Soft default", titleTiming becomes "Title timing"). Routed the two new top-level sections to tabs in SECTION_META so they no longer fall through to the catch-all "Other" tab: messageFilter to Features (alongside webSearch, summarization, memory) since it is a runtime user-message filtering feature, and skillSync to System (alongside rateLimits, balance, transactions) since it is a scheduled background sync. --- src/components/configuration/configMeta.ts | 10 ++++ src/locales/en/translation.json | 55 ++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/components/configuration/configMeta.ts b/src/components/configuration/configMeta.ts index 97c957c..2d93958 100644 --- a/src/components/configuration/configMeta.ts +++ b/src/components/configuration/configMeta.ts @@ -93,6 +93,11 @@ export const SECTION_META: Record< descriptionKey: 'com_config_section_summarization_desc', tab: 'features', }, + messageFilter: { + titleKey: 'com_config_section_messageFilter', + descriptionKey: 'com_config_section_messageFilter_desc', + tab: 'features', + }, fileConfig: { titleKey: 'com_config_section_file_config', @@ -174,6 +179,11 @@ export const SECTION_META: Record< descriptionKey: 'com_config_section_transactions_desc', tab: 'system', }, + skillSync: { + titleKey: 'com_config_section_skillSync', + descriptionKey: 'com_config_section_skillSync_desc', + tab: 'system', + }, }; /** Sections omitted from the UI entirely (legacy fields pending removal from the schema). */ diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 3f95eaa..9390387 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -654,6 +654,57 @@ "com_config_field_allowedAddresses_item": "address", "com_config_field_includeDomains_item": "domain", "com_config_field_excludeDomains_item": "domain", + "com_config_field_agent_ids": "Agent IDs", + "com_config_field_agent_ids_item": "agent ID", + "com_config_field_allowSelf": "Allow self", + "com_config_field_buildInfo": "Build info", + "com_config_field_cacheRead": "Cache read", + "com_config_field_cacheWrite": "Cache write", + "com_config_field_code": "Code", + "com_config_field_completion": "Completion", + "com_config_field_configureObo": "Configure On-Behalf-Of", + "com_config_field_contextCost": "Context cost", + "com_config_field_contextUsage": "Context usage", + "com_config_field_conversation_starters": "Conversation starters", + "com_config_field_conversation_starters_item": "starter", + "com_config_field_currency": "Currency", + "com_config_field_customPatterns": "Custom patterns", + "com_config_field_customPatterns_item": "pattern", + "com_config_field_forward_audience_on_refresh": "Forward audience on refresh", + "com_config_field_github": "GitHub", + "com_config_field_guardrailConfig": "Guardrail", + "com_config_field_guardrailIdentifier": "Guardrail identifier", + "com_config_field_guardrailVersion": "Guardrail version", + "com_config_field_hideBadgeRow": "Hide badge row", + "com_config_field_intervalMinutes": "Interval (minutes)", + "com_config_field_isTemporary": "Is temporary", + "com_config_field_maxCatalogSkills": "Max catalog skills", + "com_config_field_maxInputTokens": "Max input tokens", + "com_config_field_messageFilter": "Message filter", + "com_config_field_obo": "On-Behalf-Of", + "com_config_field_pii": "PII", + "com_config_field_proxy": "Proxy", + "com_config_field_rate": "Rate", + "com_config_field_reasoningFormat": "Reasoning format", + "com_config_field_reasoningKey": "Reasoning key", + "com_config_field_regex": "Regex", + "com_config_field_retainAgentFiles": "Retain agent files", + "com_config_field_retentionMode": "Retention mode", + "com_config_field_runOnStartup": "Run on startup", + "com_config_field_sensitive": "Sensitive", + "com_config_field_sharedLinks": "Shared links", + "com_config_field_showOnLanding": "Show on landing", + "com_config_field_skillSync": "Skill sync", + "com_config_field_softDefault": "Soft default", + "com_config_field_sources": "Sources", + "com_config_field_sources_item": "source", + "com_config_field_starterPatterns": "Starter patterns", + "com_config_field_starterPatterns_item": "pattern", + "com_config_field_streamProcessingMode": "Stream processing mode", + "com_config_field_subagents": "Subagents", + "com_config_field_titleTiming": "Title timing", + "com_config_field_tokenConfig": "Token configuration", + "com_config_field_trace": "Trace", "com_config_section_fileStrategies": "File strategies", "com_config_section_fileStrategies_desc": "Configure file handling strategies per endpoint", "com_config_section_cloudfront": "CloudFront", @@ -664,8 +715,12 @@ "com_config_section_imageOutputType_desc": "Format for generated image output", "com_config_section_includedTools": "Included tools", "com_config_section_includedTools_desc": "Tools explicitly included for availability", + "com_config_section_messageFilter": "Message filter", + "com_config_section_messageFilter_desc": "Filter or block patterns in user messages", "com_config_section_secureImageLinks": "Secure image links", "com_config_section_secureImageLinks_desc": "Enable secure, authenticated image URL delivery", + "com_config_section_skillSync": "Skill sync", + "com_config_section_skillSync_desc": "Periodically pull skill definitions from external sources", "com_config_section_summarization": "Summarization", "com_config_section_summarization_desc": "Configure conversation summarization behavior", "com_auth_title": "Admin Panel", From 92ef2a0ad6a19e9a11527cfff6f7dcf6de70f58a Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:22:50 -0700 Subject: [PATCH 3/9] =?UTF-8?q?=F0=9F=8C=90=20chore:=20Expand=20PII=20labe?= =?UTF-8?q?l,=20add=20com=5Fendpoint=5Fprompt=5Fcache=20strings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relabel com_config_field_pii from "PII" to "Personally Identifiable Information" since the parent section "Message filter" already provides the filter context. Add com_endpoint_prompt_cache (label) and com_endpoint_anthropic_prompt_cache (description) so the promptCache boolean parameter renders with a real title and explanation instead of raw i18n keys. These label keys are referenced by librechat-data-provider's Anthropic and Bedrock parameter settings (present in the package since at least 0.8.502); the admin panel locale was just missing the entries. --- src/locales/en/translation.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 9390387..e832c93 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -682,7 +682,7 @@ "com_config_field_maxInputTokens": "Max input tokens", "com_config_field_messageFilter": "Message filter", "com_config_field_obo": "On-Behalf-Of", - "com_config_field_pii": "PII", + "com_config_field_pii": "Personally Identifiable Information", "com_config_field_proxy": "Proxy", "com_config_field_rate": "Rate", "com_config_field_reasoningFormat": "Reasoning format", @@ -723,6 +723,8 @@ "com_config_section_skillSync_desc": "Periodically pull skill definitions from external sources", "com_config_section_summarization": "Summarization", "com_config_section_summarization_desc": "Configure conversation summarization behavior", + "com_endpoint_prompt_cache": "Prompt cache", + "com_endpoint_anthropic_prompt_cache": "Cache stable prompt context (system messages, tools, long inputs) at the API to reduce per-request input tokens on Anthropic models", "com_auth_title": "Admin Panel", "com_auth_email_label": "Email", "com_auth_email_placeholder": "admin@example.com", From ddbdd0221dcadc8e9baff1b4aee46f3f14c8f7dd Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:01:25 -0700 Subject: [PATCH 4/9] =?UTF-8?q?=F0=9F=AA=9F=20fix:=20Stop=20flattening=20s?= =?UTF-8?q?ingle-child=20object=20wrappers=20in=20config=20form?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FieldRenderer was passing isSoleField=true whenever the current level had exactly one field and one group, which suppressed the inner field's ConfigRow label and left the parent NestedGroup label as the only label visible. For wrappers like agents.skills = { maxCatalogSkills } and fileConfig.skills = { fileSizeLimit }, that surfaced a bare number input under a generic "Skills" header, with no way to tell which limit it was. Drop the isSoleField flattening at this site so single-child object wrappers render the inner field's label inside the parent group ("Skills > Max catalog skills: [input]"). The alwaysShowLabels prop that EndpointsRenderer used to opt out of the flattening becomes redundant, so remove it from the FieldRendererProps interface, the FieldRenderer signature, and the EndpointsRenderer call site. --- src/components/configuration/FieldRenderer.tsx | 3 +-- src/components/configuration/sections/EndpointsRenderer.tsx | 2 +- src/types/config-ui.ts | 3 --- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/components/configuration/FieldRenderer.tsx b/src/components/configuration/FieldRenderer.tsx index 0a33409..655cb65 100644 --- a/src/components/configuration/FieldRenderer.tsx +++ b/src/components/configuration/FieldRenderer.tsx @@ -1164,7 +1164,6 @@ export function FieldRenderer({ pendingResets, schemaDefaults, showConfiguredOnly, - alwaysShowLabels, }: t.FieldRendererProps) { const localize = useLocalize(); const values = @@ -1267,7 +1266,7 @@ export function FieldRenderer({ pendingResets={pendingResets} schemaDefaults={schemaDefaults} showConfiguredOnly={showConfiguredOnly} - isSoleField={!alwaysShowLabels && fields.length === 1 && groups.length === 1} + isSoleField={false} /> ); })} diff --git a/src/components/configuration/sections/EndpointsRenderer.tsx b/src/components/configuration/sections/EndpointsRenderer.tsx index ec9b764..c382731 100644 --- a/src/components/configuration/sections/EndpointsRenderer.tsx +++ b/src/components/configuration/sections/EndpointsRenderer.tsx @@ -567,7 +567,7 @@ function ProviderSection({ {hasPrioritySplit ? ( <> - + {restChildren.length > 0 && ( ; onValidationError?: (message: string) => void; From 86e411c45d3a7a40de42a90d615944ba977b7f2f Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:22:50 -0700 Subject: [PATCH 5/9] =?UTF-8?q?=E2=9C=85=20test:=20Add=20skillSync=20SAMPL?= =?UTF-8?q?E=5FOVERRIDES=20for=20config.test=20round-trip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 0.8.505 schema additions surfaced two fields whose generic control-derived sample values fail the real configSchema safeParse: skillSync.github.intervalMinutes (number) has a min-5 constraint (SKILL_SYNC_MIN_INTERVAL_MINUTES); the default sample value of 1 was rejected. skillSync.github.sources (array of objects) needs a fully-formed source entry that satisfies the GitHub source schema's id/owner/repo/paths required fields plus either credentialKey or token, since the .refine() check on the source object rejects bare strings or partial objects. Add both as path-specific overrides in SAMPLE_OVERRIDES so the config.test.ts control->value->safeParse round-trip stays green. --- src/server/config.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/server/config.test.ts b/src/server/config.test.ts index 3c34820..67a04a1 100644 --- a/src/server/config.test.ts +++ b/src/server/config.test.ts @@ -731,6 +731,10 @@ const SAMPLE_OVERRIDES: Record = { 'endpoints.agents.remoteApi.auth.oidc.issuer': 'https://example.com', 'endpoints.agents.remoteApi.auth.oidc.jwksUri': 'https://example.com/.well-known/jwks.json', 'summarization.trigger': { type: 'token_ratio', value: 0.5 }, + 'skillSync.github.intervalMinutes': 5, + 'skillSync.github.sources': [ + { id: 'sample', owner: 'foo', repo: 'bar', paths: ['skills/'], credentialKey: 'sample-key' }, + ], }; /** Generates a representative value that a given UI control would produce. */ From ad06e6ba41fc37bb228d21a128a5580efb54a8a7 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:47:10 -0700 Subject: [PATCH 6/9] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20fix:=20Surface=20SH?= =?UTF-8?q?ARED=5FLINKS=20permission=20in=20role=20editor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 0.8.505 bump added PermissionTypes.SHARED_LINKS to PERMISSION_TYPE_SCHEMA so defaultPermissions() now seeds role payloads with a sharedLinks section, but RolePermissionsPanel only renders types listed in its local PERMISSION_TYPE_ORDER and SHARED_LINKS was absent there. The result was an editable bit baked into the role payload with no UI surface to toggle it. Add PermissionTypes.SHARED_LINKS after SKILLS in PERMISSION_TYPE_ORDER so the panel renders the new multi-permission card (CREATE / SHARE / SHARE_PUBLIC). Add com_perm_type_SHARED_LINKS and com_perm_desc_SHARED_LINKS locale entries to label the card; the description stops short of "use" since the upstream sharedLinksPermissionsSchema has no USE bit. --- src/components/access/RolePermissionsPanel.tsx | 1 + src/locales/en/translation.json | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/components/access/RolePermissionsPanel.tsx b/src/components/access/RolePermissionsPanel.tsx index 20f8c72..4c31f52 100644 --- a/src/components/access/RolePermissionsPanel.tsx +++ b/src/components/access/RolePermissionsPanel.tsx @@ -13,6 +13,7 @@ const PERMISSION_TYPE_ORDER: PermissionTypes[] = [ PermissionTypes.MCP_SERVERS, PermissionTypes.REMOTE_AGENTS, PermissionTypes.SKILLS, + PermissionTypes.SHARED_LINKS, PermissionTypes.BOOKMARKS, PermissionTypes.MULTI_CONVO, PermissionTypes.TEMPORARY_CHAT, diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index e832c93..438153b 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -960,6 +960,7 @@ "com_perm_desc_MCP_SERVERS": "Connect and manage MCP tool servers", "com_perm_desc_REMOTE_AGENTS": "Connect and manage remote agent endpoints", "com_perm_desc_SKILLS": "Create, share, and use agent skills", + "com_perm_desc_SHARED_LINKS": "Create and share conversation share links", "com_perm_desc_PEOPLE_PICKER": "Control visibility of users, groups, and roles", "com_perm_type_BOOKMARKS": "Bookmarks", "com_perm_type_PROMPTS": "Prompts", @@ -976,6 +977,7 @@ "com_perm_type_MCP_SERVERS": "MCP servers", "com_perm_type_REMOTE_AGENTS": "Remote agents", "com_perm_type_SKILLS": "Skills", + "com_perm_type_SHARED_LINKS": "Shared links", "com_perm_USE": "Use", "com_perm_CREATE": "Create", "com_perm_UPDATE": "Update", From 7fe8733061d584896d1a8fb2c600f80fb998e3c7 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:50:20 -0700 Subject: [PATCH 7/9] =?UTF-8?q?=F0=9F=8C=90=20chore:=20Add=20com=5Fcap=5F*?= =?UTF-8?q?=5Fsharedlinks=20locale=20keys=20for=20SHARED=5FLINKS=20capabil?= =?UTF-8?q?ities?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 0.0.53 bump added READ_SHARED_LINKS and MANAGE_SHARED_LINKS to SystemCapabilities and bucketed both under the content category in CAPABILITY_CATEGORIES. The admin panel's Grants page renders capability labels via com_cap__, so the new capabilities surfaced as raw com_cap_read_sharedlinks and com_cap_manage_sharedlinks strings on the grants page. Add the four matching locale entries (read and manage labels plus their _desc variants) so the new capabilities render with proper names. Wording mirrors the existing skills entries since both sit in the same content category. --- src/locales/en/translation.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 438153b..52a5bf3 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -1059,6 +1059,8 @@ "com_cap_manage_prompts": "Manage prompts", "com_cap_read_skills": "Read skills", "com_cap_manage_skills": "Manage skills", + "com_cap_read_sharedlinks": "Read shared links", + "com_cap_manage_sharedlinks": "Manage shared links", "com_cap_read_assistants": "Read assistants", "com_cap_manage_assistants": "Manage assistants", "com_cap_desc_access_admin": "Full admin panel access", @@ -1079,6 +1081,8 @@ "com_cap_desc_manage_prompts": "Create, edit, and delete prompts", "com_cap_desc_read_skills": "View skill configurations", "com_cap_desc_manage_skills": "Create, edit, and delete skills", + "com_cap_desc_read_sharedlinks": "View shared conversation links", + "com_cap_desc_manage_sharedlinks": "Manage shared conversation links", "com_cap_desc_read_assistants": "View assistant configurations", "com_cap_desc_manage_assistants": "Create, edit, and delete assistants", "com_access_denied_title": "Access denied", From bb2755c2442ea214882828a0778453be6149ae60 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:59:18 -0700 Subject: [PATCH 8/9] =?UTF-8?q?=F0=9F=AA=9F=20fix:=20Gate=20MCP=20obo=20an?= =?UTF-8?q?d=20proxy=20fields=20to=20HTTP=20transports?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 0.8.505 bump added obo and proxy to the MCP server schema, but only for sse and streamable-http transports. The websocket and stdio variants type obo as ZodOptional (i.e. must stay unset) and omit proxy entirely. McpServersRenderer's visibility filter had no HTTP-only bucket; both fields fell through to the unconditional else branch and rendered in the Advanced section for every transport. An admin filling either out on stdio or websocket then hit a confusing leaf-level safeParse rejection without a transport-aware explanation. Introduce HTTP_ONLY_FIELDS and HTTP_TRANSPORTS sets that mirror REMOTE_ONLY_FIELDS / REMOTE_TRANSPORTS but exclude websocket, and gate the new obo and proxy keys through them. websocket and stdio now only see the fields their transport variant actually accepts. --- .../sections/McpServersRenderer.tsx | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/components/configuration/sections/McpServersRenderer.tsx b/src/components/configuration/sections/McpServersRenderer.tsx index 8b577fe..1a9003c 100644 --- a/src/components/configuration/sections/McpServersRenderer.tsx +++ b/src/components/configuration/sections/McpServersRenderer.tsx @@ -23,6 +23,8 @@ const TRANSPORT_FIELDS: Record = { const ALL_TRANSPORT_KEYS = new Set(Object.values(TRANSPORT_FIELDS).flat()); const REMOTE_ONLY_FIELDS = new Set(['requiresOAuth', 'apiKey', 'oauth', 'oauth_headers']); const REMOTE_TRANSPORTS = new Set(['sse', 'streamable-http', 'http', 'websocket']); +const HTTP_ONLY_FIELDS = new Set(['obo', 'proxy']); +const HTTP_TRANSPORTS = new Set(['sse', 'streamable-http', 'http']); const REQUIRED_BY_TRANSPORT: Record> = { stdio: new Set(['command', 'args']), @@ -428,6 +430,10 @@ function McpEntryFields({ if (currentTransportFields.has(field.key)) { visibleKeys.add(field.key); } + } else if (HTTP_ONLY_FIELDS.has(field.key)) { + if (HTTP_TRANSPORTS.has(currentType)) { + visibleKeys.add(field.key); + } } else if (REMOTE_ONLY_FIELDS.has(field.key)) { if (isRemote) { visibleKeys.add(field.key); @@ -646,7 +652,6 @@ function CreateMcpServerDialog({ ); } - export function McpServersRenderer(props: t.FieldRendererProps) { const { fields, @@ -667,7 +672,9 @@ export function McpServersRenderer(props: t.FieldRendererProps) { const path = parentPath; const entryPrefix = `${path}.`; const baseValue = getValue(path, parentValue ?? EMPTY_RECORD); - const baseRecord: Record = isPlainObject(baseValue) ? baseValue : EMPTY_RECORD; + const baseRecord: Record = isPlainObject(baseValue) + ? baseValue + : EMPTY_RECORD; const editsByEntry = useMemo(() => { const map = new Map>(); @@ -709,9 +716,7 @@ export function McpServersRenderer(props: t.FieldRendererProps) { seedIndex = i; } } - const subsequentLeaves = leafEdits - .slice(seedIndex + 1) - .filter((e) => e.segments.length > 0); + const subsequentLeaves = leafEdits.slice(seedIndex + 1).filter((e) => e.segments.length > 0); if (subsequentLeaves.length === 0) { return seedFromDelete ? undefined : seed; } @@ -1038,7 +1043,9 @@ const McpEntryRow = memo(function McpEntryRowImpl({ value={displayValue} onValueChange={handleWholeEntryChange} onRemove={isReadOnly || isLockedIdentity ? undefined : () => onRemove(entryKey)} - onRename={isReadOnly || isLockedIdentity ? undefined : (renamed) => onRename(entryKey, renamed)} + onRename={ + isReadOnly || isLockedIdentity ? undefined : (renamed) => onRename(entryKey, renamed) + } disabled={isReadOnly} defaultExpanded={justAdded} renderFields={renderEntryFields} @@ -1046,10 +1053,7 @@ const McpEntryRow = memo(function McpEntryRowImpl({ ); }); -function lookupLeaf( - obj: unknown, - segments: string[], -): t.ConfigValue | undefined { +function lookupLeaf(obj: unknown, segments: string[]): t.ConfigValue | undefined { let cursor: unknown = obj; for (const seg of segments) { if (!cursor || typeof cursor !== 'object' || Array.isArray(cursor)) return undefined; From 4cb8db1270cc3d958a0838130b61ea80bddb3125 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 16 Jun 2026 17:16:38 -0700 Subject: [PATCH 9/9] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20fix:=20Add=20CONFIG?= =?UTF-8?q?URE=5FOBO=20to=20MCP=5FSERVERS=20permission=20schema?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 0.8.505 bump added Permissions.CONFIGURE_OBO to mcpServersPermissionsSchema upstream, but PERMISSION_TYPE_SCHEMA[MCP_SERVERS] still only exposed USE/CREATE/SHARE/SHARE_PUBLIC. RolePermissionsPanel iterates PERMISSION_TYPE_SCHEMA exclusively, so the new CONFIGURE_OBO toggle never rendered, was never set, and was never sent in the role-save payload. The LibreChat API enforces this capability on MCP create/update routes, so admins effectively could not grant it to any role. Append Permissions.CONFIGURE_OBO to the MCP_SERVERS entry and add com_perm_CONFIGURE_OBO using the existing sentence-case-after-first style ("Configure on-behalf-of"). Also realign the com_config_field_configureObo config-field label from "Configure On-Behalf-Of" to "Configure on-behalf-of" for cross-UI consistency. --- src/constants/role.ts | 7 ++----- src/locales/en/translation.json | 3 ++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/constants/role.ts b/src/constants/role.ts index fa7cd81..dd64c49 100644 --- a/src/constants/role.ts +++ b/src/constants/role.ts @@ -40,6 +40,7 @@ export const PERMISSION_TYPE_SCHEMA: Record = { Permissions.CREATE, Permissions.SHARE, Permissions.SHARE_PUBLIC, + Permissions.CONFIGURE_OBO, ], [PermissionTypes.REMOTE_AGENTS]: [ Permissions.USE, @@ -53,11 +54,7 @@ export const PERMISSION_TYPE_SCHEMA: Record = { Permissions.SHARE, Permissions.SHARE_PUBLIC, ], - [PermissionTypes.SHARED_LINKS]: [ - Permissions.CREATE, - Permissions.SHARE, - Permissions.SHARE_PUBLIC, - ], + [PermissionTypes.SHARED_LINKS]: [Permissions.CREATE, Permissions.SHARE, Permissions.SHARE_PUBLIC], }; export function defaultPermissions(): t.RolePermissions { diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 52a5bf3..9a52c19 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -662,7 +662,7 @@ "com_config_field_cacheWrite": "Cache write", "com_config_field_code": "Code", "com_config_field_completion": "Completion", - "com_config_field_configureObo": "Configure On-Behalf-Of", + "com_config_field_configureObo": "Configure on-behalf-of", "com_config_field_contextCost": "Context cost", "com_config_field_contextUsage": "Context usage", "com_config_field_conversation_starters": "Conversation starters", @@ -989,6 +989,7 @@ "com_perm_VIEW_GROUPS": "View groups", "com_perm_VIEW_ROLES": "View roles", "com_perm_SHARE_PUBLIC": "Share publicly", + "com_perm_CONFIGURE_OBO": "Configure on-behalf-of", "com_help_title": "Help", "com_help_subtitle": "Documentation, guides, and support resources", "com_help_resources": "Resources",