Skip to content

Commit fce9596

Browse files
dustinhealyupman
andauthored
🪢 feat: Langfuse Connection Configuration (#94)
* feat: add tenant Langfuse config section Surface a per-tenant Langfuse connection section (enabled, base URL, public key, secret key) in the admin config UI. It saves through the existing /api/admin/config field API. The pinned librechat-data-provider (0.8.509) predates the langfuse config group, so a forward-compat shim extends configSchema locally until a data-provider version defining langfuse is published and pinned, mirroring the READ_AUDIT_LOG capability shim. The shim no-ops once upstream ships it. * feat: branded Langfuse connection renderer with test + masked secret Custom section renderer for the Langfuse config: enable toggle, host, public key, a masked (PasswordInput) secret that is write-only and only sent on change, the configured-key fingerprint returned by the backend, and a Test connection action. Adds an admin-gated testLangfuseConnectionFn that validates credentials against the Langfuse public projects endpoint. * fix: render Langfuse section via custom renderer and read saved values Inject the langfuse section as a SchemaField instead of extending the pinned data-provider schema, which mixed zod v4 (app) with v3 (data-provider) and left the section unintrospected so it fell back to the generic renderer. Read saved values from parentValue (the base config slice) rather than getValue leaf paths, which only resolve edited/scope values, so a configured connection repopulates on reload with the secret redacted and its fingerprint shown. * fix: drop em dash from saved-secret placeholder * feat: show loading state on Langfuse test connection button * fix: align Langfuse enable toggle with standard ConfigRow layout * test: cover Langfuse config renderer states and connection test * fix(langfuse): align connection UI with LibreChat API * fix(langfuse): gate admin settings on fanout * fix(langfuse): allow section-scoped config admins * fix(langfuse): reflect connection in configured state * fix(langfuse): simplify export enablement controls * fix(langfuse): preserve schema on startup config failure * fix(langfuse): invalidate stale verification results * fix(langfuse): preserve drafts across connection refresh * test(langfuse): protect save and enable behavior * fix(langfuse): retry transient verification failures * fix(ui): rename Langfuse connection setting * 🛂 fix: Skip Langfuse connection verification for read-only viewers The load-time effect called testLangfuseConnectionFn, which requires manage:configs:langfuse, without checking the section's disabled (read-only) prop, so a read-only viewer would trigger a failing verification on every visit. Guard the effect on disabled and add a regression test. * 🛂 fix: Show read-only Langfuse connections as unverified, not unconfigured The read-only guard forced the verification state to idle, which renders as "not configured" and misleads viewers who can still see the stored, masked connection. A configured connection viewed read-only now shows as unverified instead, and the in-flight request marker and tested-connection ref are cleared so switching back to an editable view re-verifies from scratch rather than skipping on a stale marker. * 🛂 fix: Keep a de-allowlisted Langfuse destination selectable The connection-load effect and handleCancel blanked the stored destination when the server dropped it from the allowlist, which set destinationChanged, forced edit mode, and left an enabled connection impossible to disable until a replacement was picked. Preserve the stored destination instead, so disable stays available; a de-allowlisted destination simply shows as unselected in the picker. Also await the read-only "not verified" label in its regression, since that label is set in a follow-up effect and a slower CI run had not painted it yet, and add a regression covering the disable action for an out-of-allowlist stored destination. --------- Co-authored-by: Ravi Kumar L <ravi.lazar@clickhouse.com>
1 parent 9fd05c5 commit fce9596

13 files changed

Lines changed: 1320 additions & 9 deletions

File tree

src/components/configuration/ConfigPage.tsx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import {
1717
resetBaseConfigFn,
1818
baseConfigOptions,
1919
saveBaseConfigFn,
20+
getLangfuseConnectionFn,
21+
LANGFUSE_CONNECTION_QUERY_KEY,
2022
} from '@/server';
2123
import {
2224
flattenObject,
@@ -38,6 +40,7 @@ import {
3840
buildSavePayload,
3941
mergeIndexedArrayEdits,
4042
partitionScopeResetPaths,
43+
withLangfuseConfiguredPath,
4144
} from './utils';
4245
import { validateMcpCrossField } from './sections/McpServersRenderer';
4346
import { ScopeSelector, ScopeTriggerButton } from './ScopeSelector';
@@ -303,7 +306,23 @@ export function ConfigPage({ initialTab, highlightField, initialScope }: t.Confi
303306
return Array.from(mapSecretPreviewPaths(scopeChangedPaths, schemaPathSet));
304307
}, [scopeChangedPaths, schemaPathSet]);
305308

306-
const activeConfiguredPaths = isEditingScope ? scopeConfiguredPaths : configuredPaths;
309+
const { data: langfuseConnection } = useQuery({
310+
queryKey: LANGFUSE_CONNECTION_QUERY_KEY,
311+
queryFn: () => getLangfuseConnectionFn(),
312+
enabled:
313+
!isEditingScope &&
314+
schemaTree.some((section) => section.key === 'langfuse') &&
315+
sectionPermissions.langfuse?.canEdit === true,
316+
retry: false,
317+
refetchOnWindowFocus: false,
318+
});
319+
320+
const baseConfiguredPaths = useMemo(
321+
() => withLangfuseConfiguredPath(configuredPaths, langfuseConnection?.configured === true),
322+
[configuredPaths, langfuseConnection?.configured],
323+
);
324+
325+
const activeConfiguredPaths = isEditingScope ? scopeConfiguredPaths : baseConfiguredPaths;
307326

308327
const tabConfiguredCounts = useMemo(() => {
309328
if (activeConfiguredPaths.size === 0) return {};

src/components/configuration/configMeta.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ export const SECTION_META: Record<
9898
descriptionKey: 'com_config_section_messageFilter_desc',
9999
tab: 'features',
100100
},
101+
langfuse: {
102+
titleKey: 'com_config_section_langfuse',
103+
descriptionKey: 'com_config_section_langfuse_desc',
104+
tab: 'features',
105+
},
101106

102107
fileConfig: {
103108
titleKey: 'com_config_section_file_config',

0 commit comments

Comments
 (0)