mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-27 04:07:05 +00:00
🪭 feat: Add opt-in Langfuse fanout gateway + collector (#13872)
* feat: add opt-in Langfuse fanout collector * feat: fan out Langfuse feedback scores * docs: prepare Langfuse fanout for OSS setup * fix: clarify Langfuse fanout collector config * test: stabilize librechat suite * test: fix upload dialog import order * fix: omit empty Langfuse tenant fields * fix: gate tenant Langfuse fanout * test: cover central Langfuse env fallback * style: format Langfuse fanout config * feat: route langfuse fanout by destination * docs: clarify langfuse compose destination scope * test: remove unrelated suite stabilization * style: sort agent imports * fix: treat blank tenant fanout toggle as disabled * fix: rename tenant fanout emergency toggle * test: guard langfuse fanout collector config drift * feat: tune langfuse fanout batching * test: render fanout helm tests without dependencies * fix: narrow remote agent run config * refactor: share string normalization helper * fix: align langfuse fanout env parsing * fix(langfuse): align score fanout toggles with traces * fix(langfuse): keep central fanout config collector-only * fix(langfuse): type fanout collector config * fix(langfuse): harden tenant fanout config * feat(langfuse): support media fanout gateway * fix(langfuse): route tenant fanout through destination URL * fix(langfuse): harden fanout routing checks * ci(langfuse): test fanout gateway changes * ci(langfuse): check fanout go formatting * fix(langfuse): satisfy api typecheck
This commit is contained in:
parent
0789a04d11
commit
a0529c9af7
38 changed files with 5699 additions and 130 deletions
|
|
@ -11,6 +11,8 @@ jest.mock('@librechat/agents', () => ({
|
|||
jest.mock('@librechat/api', () => ({
|
||||
unescapeLaTeX: jest.fn((x) => x),
|
||||
countTokens: jest.fn().mockResolvedValue(10),
|
||||
sendFeedbackScore: jest.fn().mockResolvedValue(undefined),
|
||||
traceIdForMessage: jest.fn((messageId) => `trace-${messageId}`),
|
||||
}));
|
||||
|
||||
jest.mock('@librechat/data-schemas', () => ({
|
||||
|
|
@ -49,6 +51,7 @@ jest.mock('~/server/middleware/requireJwtAuth', () => (req, res, next) => next()
|
|||
jest.mock('~/server/middleware', () => ({
|
||||
requireJwtAuth: (req, res, next) => next(),
|
||||
validateMessageReq: (req, res, next) => next(),
|
||||
configMiddleware: (req, res, next) => next(),
|
||||
}));
|
||||
|
||||
jest.mock('~/db/models', () => ({
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ const {
|
|||
mergeQuotedTextForCount,
|
||||
} = require('@librechat/api');
|
||||
const { findAllArtifacts, replaceArtifactContent } = require('~/server/services/Artifacts/update');
|
||||
const { requireJwtAuth, validateMessageReq } = require('~/server/middleware');
|
||||
const { requireJwtAuth, validateMessageReq, configMiddleware } = require('~/server/middleware');
|
||||
const db = require('~/models');
|
||||
|
||||
const router = express.Router();
|
||||
|
|
@ -398,49 +398,56 @@ router.put('/:conversationId/:messageId', validateMessageReq, async (req, res) =
|
|||
}
|
||||
});
|
||||
|
||||
router.put('/:conversationId/:messageId/feedback', validateMessageReq, async (req, res) => {
|
||||
try {
|
||||
const { conversationId, messageId } = req.params;
|
||||
const { feedback } = req.body;
|
||||
router.put(
|
||||
'/:conversationId/:messageId/feedback',
|
||||
validateMessageReq,
|
||||
configMiddleware,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const { conversationId, messageId } = req.params;
|
||||
const { feedback } = req.body;
|
||||
|
||||
const updatedMessage = await db.updateMessage(
|
||||
req?.user?.id,
|
||||
{
|
||||
messageId,
|
||||
feedback: feedback || null,
|
||||
},
|
||||
{ context: 'updateFeedback' },
|
||||
);
|
||||
|
||||
// Best-effort: Assistants messages do not have deterministic AgentRun traces.
|
||||
if (!isAssistantsEndpoint(updatedMessage.endpoint)) {
|
||||
sendFeedbackScore({
|
||||
traceId: traceIdForMessage(messageId),
|
||||
feedback: updatedMessage.feedback,
|
||||
metadata: {
|
||||
messageId: updatedMessage.messageId ?? messageId,
|
||||
parentMessageId: updatedMessage.parentMessageId,
|
||||
conversationId: updatedMessage.conversationId ?? conversationId,
|
||||
sessionId: updatedMessage.conversationId ?? conversationId,
|
||||
userId: req?.user?.id,
|
||||
endpoint: updatedMessage.endpoint,
|
||||
sender: updatedMessage.sender,
|
||||
isCreatedByUser: updatedMessage.isCreatedByUser,
|
||||
tokenCount: updatedMessage.tokenCount,
|
||||
const updatedMessage = await db.updateMessage(
|
||||
req?.user?.id,
|
||||
{
|
||||
messageId,
|
||||
feedback: feedback || null,
|
||||
},
|
||||
}).catch((err) => logger.error('[langfuse] feedback score failed:', err));
|
||||
}
|
||||
{ context: 'updateFeedback' },
|
||||
);
|
||||
|
||||
res.json({
|
||||
messageId,
|
||||
conversationId,
|
||||
feedback: updatedMessage.feedback,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error updating message feedback:', error);
|
||||
res.status(500).json({ error: 'Failed to update feedback' });
|
||||
}
|
||||
});
|
||||
// Best-effort: Assistants messages do not have deterministic AgentRun traces.
|
||||
if (!isAssistantsEndpoint(updatedMessage.endpoint)) {
|
||||
sendFeedbackScore({
|
||||
traceId: traceIdForMessage(messageId),
|
||||
feedback: updatedMessage.feedback,
|
||||
appConfig: req.config,
|
||||
metadata: {
|
||||
messageId: updatedMessage.messageId ?? messageId,
|
||||
parentMessageId: updatedMessage.parentMessageId,
|
||||
conversationId: updatedMessage.conversationId ?? conversationId,
|
||||
sessionId: updatedMessage.conversationId ?? conversationId,
|
||||
userId: req?.user?.id,
|
||||
tenantId: req?.user?.tenantId,
|
||||
endpoint: updatedMessage.endpoint,
|
||||
sender: updatedMessage.sender,
|
||||
isCreatedByUser: updatedMessage.isCreatedByUser,
|
||||
tokenCount: updatedMessage.tokenCount,
|
||||
},
|
||||
}).catch((err) => logger.error('[langfuse] feedback score failed:', err));
|
||||
}
|
||||
|
||||
res.json({
|
||||
messageId,
|
||||
conversationId,
|
||||
feedback: updatedMessage.feedback,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error updating message feedback:', error);
|
||||
res.status(500).json({ error: 'Failed to update feedback' });
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
router.delete('/:conversationId/:messageId', validateMessageReq, async (req, res) => {
|
||||
try {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue