@directus/api
Version:
Directus is a real-time API and App dashboard for managing SQL database content
53 lines (52 loc) • 2.87 kB
JavaScript
//#region src/ai/telemetry/langfuse.ts
const getStringAttribute = (attributes, key) => {
const value = attributes[key];
return typeof value === "string" && value.length > 0 ? value : void 0;
};
/**
* Langfuse's OTel integration doesn't automatically pick up AI SDK span attributes for input/output display.
* This processor copies ai.prompt.* / ai.response.* attributes into the langfuse.* namespace as a workaround.
*/
const createLangfuseInputOutputCompatSpanProcessor = () => {
return {
onStart() {},
onEnd(span) {
const attributes = span?.attributes;
if (!attributes || typeof attributes !== "object") return;
if (typeof span?.name !== "string" || !span.name.startsWith("ai.")) return;
const observationInput = getStringAttribute(attributes, "langfuse.observation.input");
const traceInput = getStringAttribute(attributes, "langfuse.trace.input");
const fallbackInput = getStringAttribute(attributes, "ai.prompt.messages") ?? getStringAttribute(attributes, "ai.prompt");
const input = observationInput ?? traceInput ?? fallbackInput;
const observationOutput = getStringAttribute(attributes, "langfuse.observation.output");
const traceOutput = getStringAttribute(attributes, "langfuse.trace.output");
const fallbackOutput = getStringAttribute(attributes, "ai.response.text") ?? getStringAttribute(attributes, "ai.response.object");
const output = observationOutput ?? traceOutput ?? fallbackOutput;
if (!observationInput && input) attributes["langfuse.observation.input"] = input;
if (!traceInput && input) attributes["langfuse.trace.input"] = input;
if (!observationOutput && output) attributes["langfuse.observation.output"] = output;
if (!traceOutput && output) attributes["langfuse.trace.output"] = output;
},
forceFlush: async () => {},
shutdown: async () => {}
};
};
const applyLangfuseEnv = (env) => {
const secretKey = env["LANGFUSE_SECRET_KEY"];
const publicKey = env["LANGFUSE_PUBLIC_KEY"];
const baseUrl = env["LANGFUSE_BASE_URL"];
if (typeof secretKey === "string" && secretKey.length > 0) process.env["LANGFUSE_SECRET_KEY"] = secretKey;
if (typeof publicKey === "string" && publicKey.length > 0) process.env["LANGFUSE_PUBLIC_KEY"] = publicKey;
if (typeof baseUrl === "string" && baseUrl.length > 0) process.env["LANGFUSE_BASE_URL"] = baseUrl;
};
const initLangfuse = async (env) => {
applyLangfuseEnv(env);
const [{ LangfuseSpanProcessor }, { NodeTracerProvider }] = await Promise.all([import("@langfuse/otel"), import("@opentelemetry/sdk-trace-node")]);
const tracerProvider = new NodeTracerProvider({ spanProcessors: [createLangfuseInputOutputCompatSpanProcessor(), new LangfuseSpanProcessor()] });
return {
recordIO: env["AI_TELEMETRY_RECORD_IO"] === true,
tracerProvider
};
};
//#endregion
export { applyLangfuseEnv, createLangfuseInputOutputCompatSpanProcessor, initLangfuse };