mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-07-11 00:33:40 +00:00
fix: align langfuse fanout env parsing
This commit is contained in:
parent
be4d874cef
commit
fcf2a89189
5 changed files with 72 additions and 14 deletions
|
|
@ -1383,6 +1383,38 @@ describe('Langfuse run config', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('only disables tenant fanout export when the emergency toggle is true', async () => {
|
||||
process.env.LANGFUSE_PUBLIC_KEY = 'pk-central';
|
||||
process.env.LANGFUSE_SECRET_KEY = 'sk-central';
|
||||
process.env.LANGFUSE_FANOUT_ENABLED = 'true';
|
||||
process.env.LANGFUSE_FANOUT_COLLECTOR_URL = 'http://collector-from-env:4318';
|
||||
process.env.LANGFUSE_FANOUT_TENANT_EXPORT_DISABLED = '1';
|
||||
|
||||
const callArgs = await callAndCaptureRunConfig({
|
||||
tenantId: 'tenant-1',
|
||||
appConfig: {
|
||||
langfuse: {
|
||||
publicKey: 'pk-tenant-1',
|
||||
secretKey: 'sk-tenant-1',
|
||||
baseUrl: 'https://cloud.langfuse.com',
|
||||
},
|
||||
} as AppConfig,
|
||||
});
|
||||
|
||||
expect(callArgs.langfuse).toEqual({
|
||||
deterministicTraceId: true,
|
||||
baseUrl: 'http://collector-from-env:4318',
|
||||
metadata: { 'librechat.tenant.id': 'tenant-1' },
|
||||
publicKey: 'pk-tenant-1',
|
||||
secretKey: 'sk-tenant-1',
|
||||
tags: ['tenant:tenant-1'],
|
||||
librechatTraceAttributes: {
|
||||
'librechat.langfuse.tenant_export.enabled': 'true',
|
||||
'librechat.langfuse.destination': 'eu',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('lets tenant fanout.enabled=false override deployment fanout env', async () => {
|
||||
process.env.LANGFUSE_FANOUT_ENABLED = 'true';
|
||||
process.env.LANGFUSE_FANOUT_COLLECTOR_URL = 'http://collector-from-env:4318';
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { AppConfig } from '@librechat/data-schemas';
|
|||
import type { RunConfig } from '@librechat/agents';
|
||||
import { resolveLangfuseTenantDestination } from './tenantDestinations';
|
||||
import { normalizeString } from '~/utils/text';
|
||||
import { isTrueEnv } from './utils';
|
||||
import { isEnabled } from '~/utils';
|
||||
|
||||
type LangfuseRunConfig = NonNullable<RunConfig['langfuse']>;
|
||||
type LangfuseRunConfigWithTraceAttributes = LangfuseRunConfig & {
|
||||
|
|
@ -12,7 +12,7 @@ const TENANT_EXPORT_ATTRIBUTE = 'librechat.langfuse.tenant_export.enabled';
|
|||
const TENANT_DESTINATION_ATTRIBUTE = 'librechat.langfuse.destination';
|
||||
|
||||
function isTenantExportEnabled(): boolean {
|
||||
return !isTrueEnv(process.env.LANGFUSE_FANOUT_TENANT_EXPORT_DISABLED);
|
||||
return !isEnabled(process.env.LANGFUSE_FANOUT_TENANT_EXPORT_DISABLED);
|
||||
}
|
||||
|
||||
function mergeTraceMetadata(
|
||||
|
|
@ -70,7 +70,7 @@ export function buildLangfuseConfig({
|
|||
const fanout = config?.fanout;
|
||||
const fanoutEnabled =
|
||||
fanout?.enabled !== false &&
|
||||
(fanout?.enabled === true || process.env.LANGFUSE_FANOUT_ENABLED === 'true');
|
||||
(fanout?.enabled === true || isEnabled(process.env.LANGFUSE_FANOUT_ENABLED));
|
||||
const fanoutCollectorUrl =
|
||||
normalizeString(fanout?.collectorUrl) ??
|
||||
normalizeString(process.env.LANGFUSE_FANOUT_COLLECTOR_URL);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import type { AppConfig } from '@librechat/data-schemas';
|
||||
import { resolveLangfuseTenantDestination } from './tenantDestinations';
|
||||
import { isFalseEnv, isTrueEnv, toBasicAuthorization } from './utils';
|
||||
import { toBasicAuthorization } from './utils';
|
||||
import { normalizeString } from '~/utils/text';
|
||||
import { isEnabled } from '~/utils';
|
||||
|
||||
const DEFAULT_BASE_URL = 'https://cloud.langfuse.com';
|
||||
|
||||
|
|
@ -21,7 +22,7 @@ function isSampleRateEnabled(value?: string): boolean {
|
|||
|
||||
function isTracingEnabled(): boolean {
|
||||
return (
|
||||
!isFalseEnv(process.env.LANGFUSE_TRACING_ENABLED) &&
|
||||
process.env.LANGFUSE_TRACING_ENABLED?.trim().toLowerCase() !== 'false' &&
|
||||
isSampleRateEnabled(process.env.LANGFUSE_SAMPLE_RATE)
|
||||
);
|
||||
}
|
||||
|
|
@ -66,7 +67,7 @@ function getTenantScoreDestination(appConfig?: AppConfig): LangfuseScoreDestinat
|
|||
if (!isTracingEnabled()) {
|
||||
return undefined;
|
||||
}
|
||||
if (isTrueEnv(process.env.LANGFUSE_FANOUT_TENANT_EXPORT_DISABLED)) {
|
||||
if (isEnabled(process.env.LANGFUSE_FANOUT_TENANT_EXPORT_DISABLED)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -396,6 +396,39 @@ describe('Langfuse feedback scores', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('only disables tenant scores when the emergency toggle is true', async () => {
|
||||
process.env.LANGFUSE_FANOUT_CENTRAL_AUTH_HEADER = 'Basic central-auth';
|
||||
process.env.LANGFUSE_FANOUT_CENTRAL_BASE_URL = 'http://central-langfuse:3000';
|
||||
process.env.LANGFUSE_FANOUT_TENANT_EXPORT_DISABLED = '1';
|
||||
const { sendFeedbackScore } = await loadFeedback();
|
||||
|
||||
await sendFeedbackScore({
|
||||
traceId: 'trace-id',
|
||||
feedback: { rating: 'thumbsUp' },
|
||||
appConfig: appConfigWithLangfuse({
|
||||
publicKey: 'tenant-public-key',
|
||||
secretKey: 'tenant-secret-key',
|
||||
baseUrl: 'https://cloud.langfuse.com',
|
||||
}),
|
||||
});
|
||||
|
||||
expect(getFetchMock()).toHaveBeenCalledTimes(2);
|
||||
expect(getFetchMock()).toHaveBeenCalledWith(
|
||||
'http://central-langfuse:3000/api/public/scores',
|
||||
expect.objectContaining({
|
||||
method: 'POST',
|
||||
headers: expect.objectContaining({ Authorization: 'Basic central-auth' }),
|
||||
}),
|
||||
);
|
||||
expect(getFetchMock()).toHaveBeenCalledWith(
|
||||
'https://cloud.langfuse.com/api/public/scores',
|
||||
expect.objectContaining({
|
||||
method: 'POST',
|
||||
headers: expect.objectContaining({ Authorization: getTenantAuthorization() }),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('deduplicates matching central and tenant score destinations', async () => {
|
||||
process.env.LANGFUSE_FANOUT_CENTRAL_AUTH_HEADER = getTenantAuthorization();
|
||||
process.env.LANGFUSE_FANOUT_CENTRAL_BASE_URL = 'http://shared-langfuse:3000';
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
export function isFalseEnv(value?: string): boolean {
|
||||
return value != null && ['0', 'false', 'no', 'off'].includes(value.trim().toLowerCase());
|
||||
}
|
||||
|
||||
export function isTrueEnv(value?: string): boolean {
|
||||
return value != null && ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());
|
||||
}
|
||||
|
||||
export function toBasicAuthorization(publicKey: string, secretKey: string): string {
|
||||
return `Basic ${Buffer.from(`${publicKey}:${secretKey}`).toString('base64')}`;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue