Repository navigation
feat(plugins): add langfuse plugin - #6577
Conversation
Emits Langfuse generation traces (prompt, response, model, usage, latency, errors) for every LLM completion via the existing onRequest/onResponse/onError plugin hook system. Follows the request-logger/theme-manager template shape from #3473. Zero core file changes; plugin loads via the child-process plugin system, so a broken langfuse SDK cannot crash the gateway. Files: - examples/plugins/langfuse/plugin.json — manifest + configSchema - examples/plugins/langfuse/index.mjs — three hook handlers + lazy SDK init + graceful shutdown flush - examples/plugins/langfuse/README.md — install, config, privacy notes Thanks for the excellent OmniRoute!
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Code Review
This pull request introduces a new Langfuse plugin for OmniRoute, enabling LLM completion tracing with support for sampling, body redaction, and latency tracking. The review feedback highlights that the onShutdown hook is not supported by OmniRoute and should be replaced with the onDeactivate hook in both plugin.json and index.mjs. Additionally, the feedback suggests resetting the langfuseClient to null upon deactivation to allow clean re-initialization, and refining the error handling in onError to prevent fallback objects from stringifying to "[object Object]".
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| "hooks": { | ||
| "onRequest": true, | ||
| "onResponse": true, | ||
| "onError": true | ||
| }, |
There was a problem hiding this comment.
The onShutdown hook used in index.mjs is not a recognized lifecycle event in OmniRoute. To properly flush pending events and clean up resources when the plugin is deactivated or updated, you should register and implement the onDeactivate hook instead.
"hooks": {
"onRequest": true,
"onResponse": true,
"onError": true,
"onDeactivate": true
},| /** | ||
| * onShutdown — flush pending events before OmniRoute exits. | ||
| */ | ||
| export async function onShutdown() { | ||
| if (!langfuseClient) return; | ||
| try { | ||
| await langfuseClient.shutdownAsync(); | ||
| } catch (err) { | ||
| console.error("[langfuse] shutdown failed:", err.message); | ||
| } | ||
| } |
There was a problem hiding this comment.
OmniRoute does not support an onShutdown hook. Instead, use the onDeactivate lifecycle hook to flush pending events and clean up the client. Additionally, resetting langfuseClient to null is crucial to ensure that if the plugin is deactivated and reactivated with a new configuration (e.g., updated API keys or host), a new client is instantiated with the updated settings.
| /** | |
| * onShutdown — flush pending events before OmniRoute exits. | |
| */ | |
| export async function onShutdown() { | |
| if (!langfuseClient) return; | |
| try { | |
| await langfuseClient.shutdownAsync(); | |
| } catch (err) { | |
| console.error("[langfuse] shutdown failed:", err.message); | |
| } | |
| } | |
| /** | |
| * onDeactivate — flush pending events and clean up the client when the plugin is deactivated. | |
| */ | |
| export async function onDeactivate() { | |
| if (!langfuseClient) return; | |
| try { | |
| await langfuseClient.shutdownAsync(); | |
| } catch (err) { | |
| console.error("[langfuse] shutdown failed:", err.message); | |
| } finally { | |
| langfuseClient = null; | |
| } | |
| } |
|
|
||
| const start = ctx.metadata.__langfuseStart || Date.now(); | ||
| const body = ctx?.body || {}; | ||
| const error = ctx?.error || {}; |
There was a problem hiding this comment.
| model: body.model || "unknown", | ||
| input: truncateBody(body.messages, config.redactBody), | ||
| level: "ERROR", | ||
| statusMessage: error.message || String(error), |
There was a problem hiding this comment.
|
Merged — thank you, @chirag127! 🙏 Rebased onto the active release branch (release/v3.8.47); all checks green. |
feat(plugins): add langfuse example plugin Integrated into release/v3.8.47. (thanks @chirag127)
feat(plugins): add langfuse example plugin Integrated into release/v3.8.47. (thanks @chirag127)
Problem
OmniRoute has no first-class Langfuse observability export today. Prior core-integration OTel PRs (#4974-#5018) were closed-not-merged; issue #5410 (Langfuse + OTel + Lunary + MLflow observability) closed with nothing merged.
Proposal
Add
examples/plugins/langfuse/— an opt-in plugin mirroring therequest-logger/theme-managertemplate shape from #3473. Emits one Langfusegenerationobservation per LLM completion viaonRequest/onResponse/onErrorhooks. Zero core file changes.Files
examples/plugins/langfuse/plugin.json— manifest + configSchema (publicKey, secretKey, host, enabled, sampleRate, flushAt/Interval, redactBody)examples/plugins/langfuse/index.mjs— 3 hook handlers + lazy SDK init + graceful shutdown flushexamples/plugins/langfuse/README.md— install, config, privacy notesAlternatives considered
generationsemantics native to langfuse UITesting
Install plugin → configure with Langfuse cloud keys → run any request → confirm trace appears at https://cloud.langfuse.com/project//traces.
Impact
examples/plugins/langfuse/, 288 LOC totalsrc/,chatCore.ts,combo.ts, orpackage.jsonruntime depslangfusenpm SDK is a plugin-local dep; usersnpm install langfusein the plugin dirThanks for the excellent OmniRoute!