@librechat/agents 3.2.44 → 3.2.45
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/dist/cjs/graphs/Graph.cjs +17 -8
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/instrumentation.cjs +20 -21
- package/dist/cjs/instrumentation.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +65 -13
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/langfuseConfig.cjs +106 -0
- package/dist/cjs/langfuseConfig.cjs.map +1 -0
- package/dist/cjs/langfuseRuntimeContext.cjs +48 -0
- package/dist/cjs/langfuseRuntimeContext.cjs.map +1 -0
- package/dist/cjs/langfuseRuntimeScope.cjs +57 -0
- package/dist/cjs/langfuseRuntimeScope.cjs.map +1 -0
- package/dist/cjs/langfuseToolOutputTracing.cjs +14 -119
- package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
- package/dist/cjs/main.cjs +1 -0
- package/dist/cjs/run.cjs +25 -12
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +5 -2
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/utils/misc.cjs +17 -0
- package/dist/cjs/utils/misc.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +16 -7
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/instrumentation.mjs +22 -22
- package/dist/esm/instrumentation.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +65 -14
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/langfuseConfig.mjs +102 -0
- package/dist/esm/langfuseConfig.mjs.map +1 -0
- package/dist/esm/langfuseRuntimeContext.mjs +44 -0
- package/dist/esm/langfuseRuntimeContext.mjs.map +1 -0
- package/dist/esm/langfuseRuntimeScope.mjs +53 -0
- package/dist/esm/langfuseRuntimeScope.mjs.map +1 -0
- package/dist/esm/langfuseToolOutputTracing.mjs +13 -115
- package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
- package/dist/esm/main.mjs +2 -2
- package/dist/esm/run.mjs +21 -8
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +5 -2
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/utils/misc.mjs +17 -1
- package/dist/esm/utils/misc.mjs.map +1 -1
- package/dist/types/instrumentation.d.ts +0 -1
- package/dist/types/langfuse.d.ts +5 -1
- package/dist/types/langfuseConfig.d.ts +7 -0
- package/dist/types/langfuseRuntimeContext.d.ts +26 -0
- package/dist/types/langfuseRuntimeScope.d.ts +17 -0
- package/dist/types/langfuseToolOutputTracing.d.ts +4 -11
- package/dist/types/types/graph.d.ts +6 -0
- package/dist/types/utils/misc.d.ts +1 -0
- package/package.json +1 -1
- package/src/graphs/Graph.ts +20 -13
- package/src/instrumentation.ts +33 -29
- package/src/langfuse.ts +114 -7
- package/src/langfuseConfig.ts +214 -0
- package/src/langfuseRuntimeContext.ts +93 -0
- package/src/langfuseRuntimeScope.ts +135 -0
- package/src/langfuseToolOutputTracing.ts +25 -263
- package/src/run.ts +44 -34
- package/src/specs/deterministic-trace-id.test.ts +4 -11
- package/src/specs/langfuse-callbacks.test.ts +278 -22
- package/src/specs/langfuse-config.test.ts +10 -3
- package/src/specs/langfuse-instrumentation.test.ts +32 -12
- package/src/specs/langfuse-routing.integration.test.ts +543 -0
- package/src/specs/langfuse-runtime-context.test.ts +92 -0
- package/src/specs/langfuse-tool-output-tracing.test.ts +353 -5
- package/src/tools/ToolNode.ts +10 -5
- package/src/tools/__tests__/ToolNode.langfuse.test.ts +21 -11
- package/src/types/graph.ts +9 -0
- package/src/utils/misc.ts +18 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import type { ResolvedLangfuseToolOutputTracingConfig } from '@/langfuseRuntimeContext';
|
|
2
|
+
import type * as t from '@/types';
|
|
3
|
+
import { parseBooleanEnv } from '@/utils/misc';
|
|
4
|
+
|
|
5
|
+
export const LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT = '[tool output redacted]';
|
|
6
|
+
|
|
7
|
+
function isPresent(value: unknown): value is string {
|
|
8
|
+
return typeof value === 'string' && value.trim() !== '';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function normalizeToolName(name: string): string {
|
|
12
|
+
return name.trim().toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function normalizeToolNames(names: string[] | undefined): Set<string> {
|
|
16
|
+
const normalized = new Set<string>();
|
|
17
|
+
for (const name of names ?? []) {
|
|
18
|
+
if (isPresent(name)) {
|
|
19
|
+
normalized.add(normalizeToolName(name));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return normalized;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function parseToolNames(value: string | undefined): string[] | undefined {
|
|
26
|
+
if (!isPresent(value)) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return value
|
|
31
|
+
.split(',')
|
|
32
|
+
.map((name) => name.trim())
|
|
33
|
+
.filter((name) => name !== '');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getEnvToolOutputTracingEnabled(): boolean | undefined {
|
|
37
|
+
const traceToolOutputs = parseBooleanEnv(
|
|
38
|
+
process.env.LANGFUSE_TRACE_TOOL_OUTPUTS
|
|
39
|
+
);
|
|
40
|
+
if (traceToolOutputs != null) {
|
|
41
|
+
return traceToolOutputs;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const redactToolOutputs = parseBooleanEnv(
|
|
45
|
+
process.env.LANGFUSE_REDACT_TOOL_OUTPUTS
|
|
46
|
+
);
|
|
47
|
+
if (redactToolOutputs != null) {
|
|
48
|
+
return !redactToolOutputs;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return parseBooleanEnv(process.env.LANGFUSE_TOOL_OUTPUT_TRACING_ENABLED);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getEnvRedactedToolNames(): string[] | undefined {
|
|
55
|
+
return (
|
|
56
|
+
parseToolNames(process.env.LANGFUSE_REDACT_TOOL_OUTPUT_NAMES) ??
|
|
57
|
+
parseToolNames(process.env.LANGFUSE_REDACT_TOOL_NAMES)
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getEnvRedactionText(): string | undefined {
|
|
62
|
+
return isPresent(process.env.LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT)
|
|
63
|
+
? process.env.LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT
|
|
64
|
+
: undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getEnvToolNameMatchMode(): 'exact' | 'partial' | undefined {
|
|
68
|
+
const mode = (
|
|
69
|
+
process.env.LANGFUSE_REDACT_TOOL_OUTPUT_NAME_MATCH_MODE ??
|
|
70
|
+
process.env.LANGFUSE_REDACT_TOOL_NAME_MATCH_MODE
|
|
71
|
+
)
|
|
72
|
+
?.trim()
|
|
73
|
+
.toLowerCase();
|
|
74
|
+
if (mode === 'exact' || mode === 'partial') {
|
|
75
|
+
return mode;
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function hasEnvToolOutputTracingConfig(): boolean {
|
|
81
|
+
return (
|
|
82
|
+
getEnvToolOutputTracingEnabled() != null ||
|
|
83
|
+
getEnvRedactedToolNames() != null ||
|
|
84
|
+
getEnvRedactionText() != null ||
|
|
85
|
+
getEnvToolNameMatchMode() != null
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function resolveToolOutputTracingEnabled(
|
|
90
|
+
runConfig?: t.LangfuseToolOutputTracingConfig,
|
|
91
|
+
agentConfig?: t.LangfuseToolOutputTracingConfig
|
|
92
|
+
): boolean {
|
|
93
|
+
return (
|
|
94
|
+
agentConfig?.enabled ??
|
|
95
|
+
runConfig?.enabled ??
|
|
96
|
+
getEnvToolOutputTracingEnabled() ??
|
|
97
|
+
true
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function resolveRedactedToolNames(
|
|
102
|
+
runConfig?: t.LangfuseToolOutputTracingConfig,
|
|
103
|
+
agentConfig?: t.LangfuseToolOutputTracingConfig
|
|
104
|
+
): Set<string> {
|
|
105
|
+
return normalizeToolNames([
|
|
106
|
+
...(getEnvRedactedToolNames() ?? []),
|
|
107
|
+
...(runConfig?.redactedToolNames ?? []),
|
|
108
|
+
...(agentConfig?.redactedToolNames ?? []),
|
|
109
|
+
]);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function resolveToolNameMatchMode(
|
|
113
|
+
runConfig?: t.LangfuseToolOutputTracingConfig,
|
|
114
|
+
agentConfig?: t.LangfuseToolOutputTracingConfig
|
|
115
|
+
): 'exact' | 'partial' {
|
|
116
|
+
const modes = [
|
|
117
|
+
getEnvToolNameMatchMode(),
|
|
118
|
+
runConfig?.redactedToolNameMatchMode,
|
|
119
|
+
agentConfig?.redactedToolNameMatchMode,
|
|
120
|
+
];
|
|
121
|
+
return modes.includes('partial') ? 'partial' : 'exact';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function hasToolOutputTracingConfig(
|
|
125
|
+
runLangfuse?: t.LangfuseConfig,
|
|
126
|
+
agentLangfuse?: t.LangfuseConfig
|
|
127
|
+
): boolean {
|
|
128
|
+
return (
|
|
129
|
+
runLangfuse?.toolOutputTracing != null ||
|
|
130
|
+
agentLangfuse?.toolOutputTracing != null ||
|
|
131
|
+
hasEnvToolOutputTracingConfig()
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function resolveToolOutputTracingConfig(
|
|
136
|
+
runLangfuse?: t.LangfuseConfig,
|
|
137
|
+
agentLangfuse?: t.LangfuseConfig
|
|
138
|
+
): ResolvedLangfuseToolOutputTracingConfig {
|
|
139
|
+
const runConfig = runLangfuse?.toolOutputTracing;
|
|
140
|
+
const agentConfig = agentLangfuse?.toolOutputTracing;
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
enabled: resolveToolOutputTracingEnabled(runConfig, agentConfig),
|
|
144
|
+
redactedToolNames: resolveRedactedToolNames(runConfig, agentConfig),
|
|
145
|
+
redactedToolNameMatchMode: resolveToolNameMatchMode(runConfig, agentConfig),
|
|
146
|
+
redactionText:
|
|
147
|
+
agentConfig?.redactionText ??
|
|
148
|
+
runConfig?.redactionText ??
|
|
149
|
+
getEnvRedactionText() ??
|
|
150
|
+
LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function resolveLangfuseConfig(
|
|
155
|
+
runLangfuse?: t.LangfuseConfig,
|
|
156
|
+
agentLangfuse?: t.LangfuseConfig
|
|
157
|
+
): t.LangfuseConfig | undefined {
|
|
158
|
+
if (runLangfuse == null) {
|
|
159
|
+
return agentLangfuse;
|
|
160
|
+
}
|
|
161
|
+
if (agentLangfuse == null) {
|
|
162
|
+
return runLangfuse;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const toolNodeTracing =
|
|
166
|
+
runLangfuse.toolNodeTracing != null || agentLangfuse.toolNodeTracing != null
|
|
167
|
+
? {
|
|
168
|
+
...runLangfuse.toolNodeTracing,
|
|
169
|
+
...agentLangfuse.toolNodeTracing,
|
|
170
|
+
}
|
|
171
|
+
: undefined;
|
|
172
|
+
const toolOutputTracing =
|
|
173
|
+
runLangfuse.toolOutputTracing != null ||
|
|
174
|
+
agentLangfuse.toolOutputTracing != null
|
|
175
|
+
? {
|
|
176
|
+
...runLangfuse.toolOutputTracing,
|
|
177
|
+
...agentLangfuse.toolOutputTracing,
|
|
178
|
+
}
|
|
179
|
+
: undefined;
|
|
180
|
+
const metadata =
|
|
181
|
+
runLangfuse.metadata != null || agentLangfuse.metadata != null
|
|
182
|
+
? {
|
|
183
|
+
...runLangfuse.metadata,
|
|
184
|
+
...agentLangfuse.metadata,
|
|
185
|
+
}
|
|
186
|
+
: undefined;
|
|
187
|
+
const librechatTraceAttributes =
|
|
188
|
+
runLangfuse.librechatTraceAttributes != null ||
|
|
189
|
+
agentLangfuse.librechatTraceAttributes != null
|
|
190
|
+
? {
|
|
191
|
+
...runLangfuse.librechatTraceAttributes,
|
|
192
|
+
...agentLangfuse.librechatTraceAttributes,
|
|
193
|
+
}
|
|
194
|
+
: undefined;
|
|
195
|
+
const tags =
|
|
196
|
+
runLangfuse.tags != null || agentLangfuse.tags != null
|
|
197
|
+
? [
|
|
198
|
+
...new Set([
|
|
199
|
+
...(runLangfuse.tags ?? []),
|
|
200
|
+
...(agentLangfuse.tags ?? []),
|
|
201
|
+
]),
|
|
202
|
+
]
|
|
203
|
+
: undefined;
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
...runLangfuse,
|
|
207
|
+
...agentLangfuse,
|
|
208
|
+
...(metadata != null ? { metadata } : {}),
|
|
209
|
+
...(librechatTraceAttributes != null ? { librechatTraceAttributes } : {}),
|
|
210
|
+
...(tags != null ? { tags } : {}),
|
|
211
|
+
...(toolNodeTracing != null ? { toolNodeTracing } : {}),
|
|
212
|
+
...(toolOutputTracing != null ? { toolOutputTracing } : {}),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
3
|
+
import type * as t from '@/types';
|
|
4
|
+
|
|
5
|
+
export type ResolvedLangfuseToolOutputTracingConfig = {
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
redactedToolNames: Set<string>;
|
|
8
|
+
redactedToolNameMatchMode: 'exact' | 'partial';
|
|
9
|
+
redactionText: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type LangfuseRuntimeContext = {
|
|
13
|
+
langfuse?: t.LangfuseConfig;
|
|
14
|
+
traceIdSeed?: string;
|
|
15
|
+
toolOutputTracing?: ResolvedLangfuseToolOutputTracingConfig;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const langfuseRuntimeContextStore =
|
|
19
|
+
new AsyncLocalStorage<LangfuseRuntimeContext>();
|
|
20
|
+
|
|
21
|
+
function hasText(value: string | undefined): value is string {
|
|
22
|
+
return value != null && value.trim() !== '';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function hasLangfuseRuntimeContextValue(
|
|
26
|
+
context: LangfuseRuntimeContext
|
|
27
|
+
): boolean {
|
|
28
|
+
return (
|
|
29
|
+
context.langfuse != null ||
|
|
30
|
+
hasText(context.traceIdSeed) ||
|
|
31
|
+
context.toolOutputTracing != null
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** sha256(seed) -> first 32 hex chars; matches `@langfuse/tracing` `createTraceId`. */
|
|
36
|
+
export function traceIdFromSeed(seed: string): string {
|
|
37
|
+
return createHash('sha256').update(seed, 'utf8').digest('hex').slice(0, 32);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getLangfuseRuntimeContext():
|
|
41
|
+
| LangfuseRuntimeContext
|
|
42
|
+
| undefined {
|
|
43
|
+
return langfuseRuntimeContextStore.getStore();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getLangfuseRuntimeConfig(): t.LangfuseConfig | undefined {
|
|
47
|
+
return getLangfuseRuntimeContext()?.langfuse;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function getTraceIdSeed(): string | undefined {
|
|
51
|
+
return getLangfuseRuntimeContext()?.traceIdSeed;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function getLangfuseRuntimeToolOutputTracingConfig():
|
|
55
|
+
| ResolvedLangfuseToolOutputTracingConfig
|
|
56
|
+
| undefined {
|
|
57
|
+
return getLangfuseRuntimeContext()?.toolOutputTracing;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Runs `fn` with a merged Langfuse runtime context. Undefined fields inherit
|
|
62
|
+
* from the parent scope; callers intentionally cannot clear parent values by
|
|
63
|
+
* passing `undefined`.
|
|
64
|
+
*/
|
|
65
|
+
export function runWithLangfuseRuntimeContext<T>(
|
|
66
|
+
context: LangfuseRuntimeContext,
|
|
67
|
+
fn: () => T
|
|
68
|
+
): T {
|
|
69
|
+
const current = getLangfuseRuntimeContext();
|
|
70
|
+
const next = {
|
|
71
|
+
...(current ?? {}),
|
|
72
|
+
...(context.langfuse !== undefined ? { langfuse: context.langfuse } : {}),
|
|
73
|
+
...(hasText(context.traceIdSeed)
|
|
74
|
+
? { traceIdSeed: context.traceIdSeed }
|
|
75
|
+
: {}),
|
|
76
|
+
...(context.toolOutputTracing !== undefined
|
|
77
|
+
? { toolOutputTracing: context.toolOutputTracing }
|
|
78
|
+
: {}),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return hasLangfuseRuntimeContextValue(next)
|
|
82
|
+
? langfuseRuntimeContextStore.run(next, fn)
|
|
83
|
+
: fn();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function runWithTraceIdSeed<T>(
|
|
87
|
+
seed: string | undefined,
|
|
88
|
+
fn: () => T
|
|
89
|
+
): T {
|
|
90
|
+
return hasText(seed)
|
|
91
|
+
? runWithLangfuseRuntimeContext({ traceIdSeed: seed }, fn)
|
|
92
|
+
: fn();
|
|
93
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { context, createContextKey } from '@opentelemetry/api';
|
|
2
|
+
import type { Context } from '@opentelemetry/api';
|
|
3
|
+
import type {
|
|
4
|
+
LangfuseRuntimeContext,
|
|
5
|
+
ResolvedLangfuseToolOutputTracingConfig,
|
|
6
|
+
} from '@/langfuseRuntimeContext';
|
|
7
|
+
import type * as t from '@/types';
|
|
8
|
+
import {
|
|
9
|
+
getLangfuseRuntimeConfig,
|
|
10
|
+
getLangfuseRuntimeToolOutputTracingConfig,
|
|
11
|
+
getTraceIdSeed,
|
|
12
|
+
hasLangfuseRuntimeContextValue,
|
|
13
|
+
runWithLangfuseRuntimeContext,
|
|
14
|
+
} from '@/langfuseRuntimeContext';
|
|
15
|
+
import {
|
|
16
|
+
hasToolOutputTracingConfig,
|
|
17
|
+
resolveLangfuseConfig,
|
|
18
|
+
resolveToolOutputTracingConfig,
|
|
19
|
+
} from '@/langfuseConfig';
|
|
20
|
+
|
|
21
|
+
export type LangfuseRuntimeScope = LangfuseRuntimeContext;
|
|
22
|
+
|
|
23
|
+
export type ResolveLangfuseRuntimeScopeParams = {
|
|
24
|
+
runLangfuse?: t.LangfuseConfig;
|
|
25
|
+
langfuseOverlay?: t.LangfuseConfig;
|
|
26
|
+
traceIdSeed?: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const langfuseToolOutputTracingConfigKey = createContextKey(
|
|
30
|
+
'librechat.langfuse.tool-output-tracing'
|
|
31
|
+
);
|
|
32
|
+
const langfuseConfigKey = createContextKey('librechat.langfuse.config');
|
|
33
|
+
const langfuseTraceIdSeedKey = createContextKey(
|
|
34
|
+
'librechat.langfuse.trace-id-seed'
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
38
|
+
return value != null && typeof value === 'object' && !Array.isArray(value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function hasText(value: string | undefined): value is string {
|
|
42
|
+
return value != null && value.trim() !== '';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getOtelLangfuseConfig(
|
|
46
|
+
activeContext: Context
|
|
47
|
+
): t.LangfuseConfig | undefined {
|
|
48
|
+
const value = activeContext.getValue(langfuseConfigKey);
|
|
49
|
+
return isRecord(value) ? (value as t.LangfuseConfig) : undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function getOtelTraceIdSeed(activeContext: Context): string | undefined {
|
|
53
|
+
const value = activeContext.getValue(langfuseTraceIdSeedKey);
|
|
54
|
+
return typeof value === 'string' && value.trim() !== '' ? value : undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getOtelToolOutputTracingConfig(
|
|
58
|
+
activeContext: Context
|
|
59
|
+
): ResolvedLangfuseToolOutputTracingConfig | undefined {
|
|
60
|
+
const value = activeContext.getValue(langfuseToolOutputTracingConfigKey);
|
|
61
|
+
return isRecord(value)
|
|
62
|
+
? (value as ResolvedLangfuseToolOutputTracingConfig)
|
|
63
|
+
: undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function resolveLangfuseConfigForSpan(
|
|
67
|
+
activeContext: Context
|
|
68
|
+
): t.LangfuseConfig | undefined {
|
|
69
|
+
return getLangfuseRuntimeConfig() ?? getOtelLangfuseConfig(activeContext);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function resolveTraceIdSeedForSpan(
|
|
73
|
+
activeContext: Context
|
|
74
|
+
): string | undefined {
|
|
75
|
+
return getTraceIdSeed() ?? getOtelTraceIdSeed(activeContext);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function resolveToolOutputTracingConfigForSpan(
|
|
79
|
+
activeContext: Context
|
|
80
|
+
): ResolvedLangfuseToolOutputTracingConfig | undefined {
|
|
81
|
+
return (
|
|
82
|
+
getLangfuseRuntimeToolOutputTracingConfig() ??
|
|
83
|
+
getOtelToolOutputTracingConfig(activeContext)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function withLangfuseRuntimeScope<T>(
|
|
88
|
+
scope: LangfuseRuntimeScope,
|
|
89
|
+
action: () => T
|
|
90
|
+
): T {
|
|
91
|
+
if (!hasLangfuseRuntimeContextValue(scope)) {
|
|
92
|
+
return action();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let activeContext = context.active();
|
|
96
|
+
if (scope.langfuse != null) {
|
|
97
|
+
activeContext = activeContext.setValue(langfuseConfigKey, scope.langfuse);
|
|
98
|
+
}
|
|
99
|
+
if (scope.toolOutputTracing != null) {
|
|
100
|
+
activeContext = activeContext.setValue(
|
|
101
|
+
langfuseToolOutputTracingConfigKey,
|
|
102
|
+
scope.toolOutputTracing
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
if (hasText(scope.traceIdSeed)) {
|
|
106
|
+
activeContext = activeContext.setValue(
|
|
107
|
+
langfuseTraceIdSeedKey,
|
|
108
|
+
scope.traceIdSeed
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Span processors receive the OTel parent context in `onStart`, while
|
|
113
|
+
// LangChain callback handlers may run outside that context and need ALS.
|
|
114
|
+
// The trace id generator reads the seed from ALS or OTel context so SDK
|
|
115
|
+
// callbacks that preserve only one of those contexts still keep trace/score
|
|
116
|
+
// cohesion.
|
|
117
|
+
return runWithLangfuseRuntimeContext(scope, () =>
|
|
118
|
+
context.with(activeContext, action)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function resolveLangfuseRuntimeScope({
|
|
123
|
+
runLangfuse,
|
|
124
|
+
langfuseOverlay,
|
|
125
|
+
traceIdSeed,
|
|
126
|
+
}: ResolveLangfuseRuntimeScopeParams): LangfuseRuntimeScope {
|
|
127
|
+
const langfuse = resolveLangfuseConfig(runLangfuse, langfuseOverlay);
|
|
128
|
+
const toolOutputTracing = !hasToolOutputTracingConfig(
|
|
129
|
+
runLangfuse,
|
|
130
|
+
langfuseOverlay
|
|
131
|
+
)
|
|
132
|
+
? undefined
|
|
133
|
+
: resolveToolOutputTracingConfig(runLangfuse, langfuseOverlay);
|
|
134
|
+
return { langfuse, traceIdSeed, toolOutputTracing };
|
|
135
|
+
}
|