pi-langfuse 1.5.15 → 1.5.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/langfuse.ts +32 -1
package/package.json
CHANGED
package/src/langfuse.ts
CHANGED
|
@@ -458,6 +458,32 @@ function observationType(asType?: string): FallbackObservationType {
|
|
|
458
458
|
return asType === "generation" ? "GENERATION" : "SPAN";
|
|
459
459
|
}
|
|
460
460
|
|
|
461
|
+
/**
|
|
462
|
+
* Langfuse stamps propagated attributes onto a span in
|
|
463
|
+
* `LangfuseSpanProcessor.onStart(span, parentContext)`, reading them from the
|
|
464
|
+
* OTel context that was active when the span was created. `propagateAttributes`
|
|
465
|
+
* only seeds that context for the duration of its callback, so a child created
|
|
466
|
+
* later — from a separate event handler, outside the callback — is written with
|
|
467
|
+
* an empty `session.id`.
|
|
468
|
+
*
|
|
469
|
+
* That is invisible in the legacy data model, where the session lives on the
|
|
470
|
+
* trace, but Langfuse v4 stores `session_id` per event row and aggregates a
|
|
471
|
+
* session with `WHERE session_id != ''`. Unstamped children drop out of
|
|
472
|
+
* `sumMap(cost_details)` and `sumMap(usage_details)`, which is why such
|
|
473
|
+
* sessions report their trace count correctly but no cost and no usage at all.
|
|
474
|
+
*
|
|
475
|
+
* Re-entering the propagated context for every child keeps the whole tree in
|
|
476
|
+
* the session. The id is read back off the parent span rather than from
|
|
477
|
+
* `state.currentSessionId`, so a child created outside an active session scope
|
|
478
|
+
* still inherits whatever its parent was actually stamped with.
|
|
479
|
+
*/
|
|
480
|
+
const OTEL_SESSION_ID_ATTRIBUTE = "session.id";
|
|
481
|
+
|
|
482
|
+
function readSessionId(observation: any): string | undefined {
|
|
483
|
+
const value = observation?.otelSpan?.attributes?.[OTEL_SESSION_ID_ATTRIBUTE];
|
|
484
|
+
return typeof value === "string" && value ? value : undefined;
|
|
485
|
+
}
|
|
486
|
+
|
|
461
487
|
function wrapObservation(
|
|
462
488
|
observation: any,
|
|
463
489
|
store: RestFallbackStore,
|
|
@@ -517,7 +543,12 @@ function wrapObservation(
|
|
|
517
543
|
return observation.end();
|
|
518
544
|
},
|
|
519
545
|
startObservation(childName: string, childBody?: Record<string, unknown>, options?: { asType?: string }) {
|
|
520
|
-
const
|
|
546
|
+
const inheritedSessionId = readSessionId(observation) ?? state.currentSessionId ?? undefined;
|
|
547
|
+
const propagate = runtime?.propagateAttributes;
|
|
548
|
+
const createChild = () => observation.startObservation(childName, childBody, options);
|
|
549
|
+
const child = inheritedSessionId && propagate
|
|
550
|
+
? propagate({ sessionId: inheritedSessionId.slice(0, 200) }, createChild)
|
|
551
|
+
: createChild();
|
|
521
552
|
return wrapObservation(child, store, childName, childBody, options?.asType, id);
|
|
522
553
|
},
|
|
523
554
|
setTraceIO(traceBody?: { input?: unknown; output?: unknown }) {
|