Files
ask262/src/lib/langfuse-transport.ts
T
bendtherules d71726205d feat(langfuse): add tool-level spans with input/output and trace-level I/O
Each MCP tool handler now sets:
- LANGFUSE_TRACE_OUTPUT_ATTR on tool spans (maps to top-level trace output)
- LANGFUSE_OBSERVATION_INPUT_ATTR and LANGFUSE_OBSERVATION_OUTPUT_ATTR
  for detailed child observation views

HTTP root span renamed to 'mcp_http_request' for consistency with stdio.
All attribute keys use constants from langfuse-transport.ts.
2026-04-27 18:56:50 +05:30

75 lines
2.4 KiB
TypeScript

import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { LangfuseSpanProcessor } from "@langfuse/otel";
/** Trace name used for HTTP transport in Langfuse. */
export const TRACE_NAME_HTTP = "ask262-http";
/** Trace name used for stdio transport in Langfuse. */
export const TRACE_NAME_STDIO = "ask262-stdio";
/** Langfuse attribute key for setting the trace name on a span. */
export const LANGFUSE_TRACE_NAME_ATTR = "langfuse.trace.name";
/** Langfuse attribute key for observation input. */
export const LANGFUSE_OBSERVATION_INPUT_ATTR = "langfuse.observation.input";
/** Langfuse attribute key for observation output. */
export const LANGFUSE_OBSERVATION_OUTPUT_ATTR = "langfuse.observation.output";
/** Langfuse attribute key for trace-level input. */
export const LANGFUSE_TRACE_INPUT_ATTR = "langfuse.trace.input";
/** Langfuse attribute key for trace-level output. */
export const LANGFUSE_TRACE_OUTPUT_ATTR = "langfuse.trace.output";
let provider: NodeTracerProvider | null = null;
/**
* Extract MCP tool call information from a JSON-RPC request body.
* Used to populate trace-level input in Langfuse.
*/
export function extractMcpToolInfo(
body: unknown,
): { method?: string; tool?: string; input?: unknown } {
if (typeof body !== "object" || body === null) return {};
const b = body as Record<string, unknown>;
const rpcMethod = b.method as string | undefined;
if (rpcMethod === "tools/call") {
const params = b.params as Record<string, unknown> | undefined;
return {
method: rpcMethod,
tool: params?.name as string | undefined,
input: params?.arguments,
};
}
return { method: rpcMethod };
}
/**
* Initialize Langfuse OTel span processor.
* Called once at server startup before any spans are created.
*/
export function initializeLangfuseTransport(): void {
if (process.env.ASK262_LANGFUSE_ENABLED !== "true") return;
const publicKey = process.env.LANGFUSE_PUBLIC_KEY;
const secretKey = process.env.LANGFUSE_SECRET_KEY;
if (!publicKey || !secretKey) {
console.error(
"[LANGFUSE] Missing LANGFUSE_PUBLIC_KEY or LANGFUSE_SECRET_KEY, skipping",
);
return;
}
provider = new NodeTracerProvider({
spanProcessors: [
new LangfuseSpanProcessor({
// Export all spans, not just LLM-relevant ones
shouldExportSpan: () => true,
}),
],
});
provider.register();
}