pi-langfuse 1.4.2 → 1.4.3
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/constants.ts +1 -0
- package/src/handlers/agent.ts +2 -0
- package/src/handlers/generation.ts +6 -6
- package/src/handlers/tool.ts +3 -3
- package/src/handlers/turn.ts +2 -2
- package/src/langfuse.ts +20 -3
- package/src/state.ts +9 -0
- package/src/utils.ts +35 -4
- package/types/langfuse-runtime-shims.d.ts +49 -0
package/package.json
CHANGED
package/src/constants.ts
CHANGED
package/src/handlers/agent.ts
CHANGED
|
@@ -19,6 +19,7 @@ export function updateTraceIO(input?: unknown, output?: unknown) {
|
|
|
19
19
|
|
|
20
20
|
export async function startAgentRun(event: Record<string, unknown>, ctx: any) {
|
|
21
21
|
if (!(await ensureConfig(ctx))) {
|
|
22
|
+
state.isTracingDisabled = true;
|
|
22
23
|
return;
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -92,6 +93,7 @@ export async function startAgentRun(event: Record<string, unknown>, ctx: any) {
|
|
|
92
93
|
updateTraceIO(promptInput, undefined);
|
|
93
94
|
} catch (e) {
|
|
94
95
|
console.warn("📊 Langfuse: Failed to create agent observation", e);
|
|
96
|
+
state.isTracingDisabled = true;
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
99
|
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import type { GenerationState, ObservationUpdate } from "../types.js";
|
|
14
14
|
|
|
15
15
|
export function getOpenGeneration(): GenerationState | undefined {
|
|
16
|
-
if (!state.agentState) {
|
|
16
|
+
if (state.isTracingDisabled || !state.agentState) {
|
|
17
17
|
return undefined;
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -29,7 +29,7 @@ export function getOpenGeneration(): GenerationState | undefined {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export async function startGeneration(event: Record<string, unknown>) {
|
|
32
|
-
if (!state.agentState?.root) {
|
|
32
|
+
if (state.isTracingDisabled || !state.agentState?.root) {
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -79,7 +79,7 @@ export async function startGeneration(event: Record<string, unknown>) {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export function updateGenerationMetadata(event: Record<string, unknown>) {
|
|
82
|
-
if (!state.agentState) {
|
|
82
|
+
if (state.isTracingDisabled || !state.agentState) {
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
85
|
|
|
@@ -132,7 +132,7 @@ export function updateGenerationMetadata(event: Record<string, unknown>) {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
export function recordTTFT(event: Record<string, unknown>) {
|
|
135
|
-
if (!state.agentState) {
|
|
135
|
+
if (state.isTracingDisabled || !state.agentState) {
|
|
136
136
|
return;
|
|
137
137
|
}
|
|
138
138
|
|
|
@@ -150,7 +150,7 @@ export function recordTTFT(event: Record<string, unknown>) {
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
export async function finishGenerationFromMessage(event: Record<string, unknown>) {
|
|
153
|
-
if (!state.agentState) {
|
|
153
|
+
if (state.isTracingDisabled || !state.agentState) {
|
|
154
154
|
return;
|
|
155
155
|
}
|
|
156
156
|
|
|
@@ -190,7 +190,7 @@ export async function finishGenerationFromMessage(event: Record<string, unknown>
|
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
export async function createFallbackGenerationFromTurn(event: Record<string, unknown>, message: Record<string, unknown>) {
|
|
193
|
-
if (!state.agentState?.root || state.agentState.generationOrder.length > 0) {
|
|
193
|
+
if (state.isTracingDisabled || !state.agentState?.root || state.agentState.generationOrder.length > 0) {
|
|
194
194
|
return;
|
|
195
195
|
}
|
|
196
196
|
|
package/src/handlers/tool.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import { MAX_TOOL_PAYLOAD_LENGTH } from "../constants.js";
|
|
13
13
|
|
|
14
14
|
export async function startToolObservation(event: Record<string, unknown>) {
|
|
15
|
-
if (!state.agentState?.root) {
|
|
15
|
+
if (state.isTracingDisabled || !state.agentState?.root) {
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -59,7 +59,7 @@ export async function startToolObservation(event: Record<string, unknown>) {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
export async function finishToolObservation(event: Record<string, unknown>) {
|
|
62
|
-
if (!state.agentState) {
|
|
62
|
+
if (state.isTracingDisabled || !state.agentState) {
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -119,7 +119,7 @@ export async function finishToolObservation(event: Record<string, unknown>) {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
export function closeDanglingObservations(statusMessage: string) {
|
|
122
|
-
if (!state.agentState) {
|
|
122
|
+
if (state.isTracingDisabled || !state.agentState) {
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
125
125
|
|
package/src/handlers/turn.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { getRuntime } from "../langfuse.js";
|
|
|
3
3
|
import { shapePayload } from "../utils.js";
|
|
4
4
|
|
|
5
5
|
export async function startTurnObservation(event: Record<string, unknown>) {
|
|
6
|
-
if (!state.agentState?.root) {
|
|
6
|
+
if (state.isTracingDisabled || !state.agentState?.root) {
|
|
7
7
|
return;
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -40,7 +40,7 @@ export async function startTurnObservation(event: Record<string, unknown>) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export function finishTurnObservation(event?: Record<string, unknown>) {
|
|
43
|
-
if (!state.agentState?.activeTurn) {
|
|
43
|
+
if (state.isTracingDisabled || !state.agentState?.activeTurn) {
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
|
package/src/langfuse.ts
CHANGED
|
@@ -42,7 +42,8 @@ interface RestFallbackStore {
|
|
|
42
42
|
attempted: boolean;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
const
|
|
45
|
+
const OTEL_VISIBILITY_TIMEOUT_MS = 1_500;
|
|
46
|
+
const OTEL_VISIBILITY_POLL_INTERVAL_MS = 200;
|
|
46
47
|
|
|
47
48
|
function nowIso() {
|
|
48
49
|
return new Date().toISOString();
|
|
@@ -190,6 +191,23 @@ async function traceExists(rt: LangfuseRuntime, traceId: string): Promise<boolea
|
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
193
|
|
|
194
|
+
async function waitForTraceVisibility(rt: LangfuseRuntime, traceId: string): Promise<boolean> {
|
|
195
|
+
const deadline = Date.now() + OTEL_VISIBILITY_TIMEOUT_MS;
|
|
196
|
+
|
|
197
|
+
while (true) {
|
|
198
|
+
if (await traceExists(rt, traceId)) {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const remainingMs = deadline - Date.now();
|
|
203
|
+
if (remainingMs <= 0) {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
await delay(Math.min(OTEL_VISIBILITY_POLL_INTERVAL_MS, remainingMs));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
193
211
|
function eventTimestamp(record: { endTime?: string; startTime?: string; timestamp?: string }) {
|
|
194
212
|
return record.endTime ?? record.startTime ?? record.timestamp ?? nowIso();
|
|
195
213
|
}
|
|
@@ -201,8 +219,7 @@ async function fallbackToRestIngestion(rt: LangfuseRuntime) {
|
|
|
201
219
|
}
|
|
202
220
|
store.attempted = true;
|
|
203
221
|
|
|
204
|
-
await
|
|
205
|
-
if (await traceExists(rt, store.trace.id)) {
|
|
222
|
+
if (await waitForTraceVisibility(rt, store.trace.id)) {
|
|
206
223
|
return;
|
|
207
224
|
}
|
|
208
225
|
|
package/src/state.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface SessionRunState {
|
|
|
8
8
|
toolCallCount: number;
|
|
9
9
|
errorCount: number;
|
|
10
10
|
turnCount: number;
|
|
11
|
+
tracingDisabled: boolean;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
const DEFAULT_SESSION_ID = "__pi_langfuse_default_session__";
|
|
@@ -23,6 +24,7 @@ function createSessionRunState(): SessionRunState {
|
|
|
23
24
|
toolCallCount: 0,
|
|
24
25
|
errorCount: 0,
|
|
25
26
|
turnCount: 0,
|
|
27
|
+
tracingDisabled: false,
|
|
26
28
|
};
|
|
27
29
|
}
|
|
28
30
|
|
|
@@ -109,6 +111,13 @@ export const state = {
|
|
|
109
111
|
set turnCount(turnCount: number) {
|
|
110
112
|
getSessionRunState().turnCount = turnCount;
|
|
111
113
|
},
|
|
114
|
+
|
|
115
|
+
get isTracingDisabled() {
|
|
116
|
+
return getSessionRunState().tracingDisabled;
|
|
117
|
+
},
|
|
118
|
+
set isTracingDisabled(disabled: boolean) {
|
|
119
|
+
getSessionRunState().tracingDisabled = disabled;
|
|
120
|
+
},
|
|
112
121
|
};
|
|
113
122
|
|
|
114
123
|
export function resetRunState(sessionId = getActiveSessionId()) {
|
package/src/utils.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
MAX_ARRAY_ITEMS,
|
|
3
3
|
MAX_DEPTH,
|
|
4
4
|
MAX_OBJECT_KEYS,
|
|
5
|
+
MAX_PAYLOAD_NODES,
|
|
5
6
|
MAX_STRING_LENGTH,
|
|
6
7
|
MAX_TOOL_PAYLOAD_LENGTH,
|
|
7
8
|
} from "./constants.js";
|
|
@@ -23,11 +24,25 @@ export function tryParseJson(value: string): unknown {
|
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
const PAYLOAD_TOO_LARGE = "[payload too large]";
|
|
28
|
+
|
|
29
|
+
export function shapePayload(value: unknown, options: { maxString?: number; depth?: number; maxNodes?: number } = {}): unknown {
|
|
27
30
|
const maxString = options.maxString ?? MAX_STRING_LENGTH;
|
|
28
31
|
const depth = options.depth ?? MAX_DEPTH;
|
|
32
|
+
const maxNodes = options.maxNodes ?? MAX_PAYLOAD_NODES;
|
|
33
|
+
const budget = { exhausted: false, nodeCount: 0 };
|
|
29
34
|
|
|
30
35
|
function visit(item: unknown, remainingDepth: number, seen: WeakSet<object>): unknown {
|
|
36
|
+
if (budget.exhausted) {
|
|
37
|
+
return PAYLOAD_TOO_LARGE;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
budget.nodeCount++;
|
|
41
|
+
if (budget.nodeCount > maxNodes) {
|
|
42
|
+
budget.exhausted = true;
|
|
43
|
+
return PAYLOAD_TOO_LARGE;
|
|
44
|
+
}
|
|
45
|
+
|
|
31
46
|
if (typeof item === "string") {
|
|
32
47
|
const truncated = truncate(item, maxString);
|
|
33
48
|
const parsed = tryParseJson(truncated);
|
|
@@ -59,7 +74,15 @@ export function shapePayload(value: unknown, options: { maxString?: number; dept
|
|
|
59
74
|
}
|
|
60
75
|
|
|
61
76
|
if (Array.isArray(item)) {
|
|
62
|
-
|
|
77
|
+
const output: unknown[] = [];
|
|
78
|
+
const limit = Math.min(item.length, MAX_ARRAY_ITEMS);
|
|
79
|
+
for (let index = 0; index < limit; index++) {
|
|
80
|
+
output.push(visit(item[index], remainingDepth - 1, seen));
|
|
81
|
+
if (budget.exhausted) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return output;
|
|
63
86
|
}
|
|
64
87
|
|
|
65
88
|
if (item instanceof Error) {
|
|
@@ -77,8 +100,16 @@ export function shapePayload(value: unknown, options: { maxString?: number; dept
|
|
|
77
100
|
seen.add(item);
|
|
78
101
|
|
|
79
102
|
const output: Record<string, unknown> = {};
|
|
80
|
-
|
|
81
|
-
|
|
103
|
+
let keyCount = 0;
|
|
104
|
+
for (const key in item as Record<string, unknown>) {
|
|
105
|
+
if (!Object.hasOwn(item, key)) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
output[key] = visit((item as Record<string, unknown>)[key], remainingDepth - 1, seen);
|
|
109
|
+
keyCount++;
|
|
110
|
+
if (budget.exhausted || keyCount >= MAX_OBJECT_KEYS) {
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
82
113
|
}
|
|
83
114
|
return output;
|
|
84
115
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
declare module "@opentelemetry/sdk-trace-base" {
|
|
2
|
+
export class BasicTracerProvider {
|
|
3
|
+
constructor(options?: { spanProcessors?: unknown[] });
|
|
4
|
+
forceFlush?(): Promise<void>;
|
|
5
|
+
shutdown?(): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
declare module "@langfuse/otel" {
|
|
10
|
+
export class LangfuseSpanProcessor {
|
|
11
|
+
constructor(options: {
|
|
12
|
+
publicKey: string;
|
|
13
|
+
secretKey: string;
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
});
|
|
16
|
+
forceFlush?(): Promise<void>;
|
|
17
|
+
shutdown?(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
declare module "@langfuse/tracing" {
|
|
22
|
+
export function setLangfuseTracerProvider(provider: unknown): void;
|
|
23
|
+
|
|
24
|
+
export function startObservation(
|
|
25
|
+
name: string,
|
|
26
|
+
body?: Record<string, unknown>,
|
|
27
|
+
options?: { asType?: string },
|
|
28
|
+
): unknown;
|
|
29
|
+
|
|
30
|
+
export function propagateAttributes<T>(
|
|
31
|
+
params: {
|
|
32
|
+
sessionId?: string;
|
|
33
|
+
traceName?: string;
|
|
34
|
+
metadata?: Record<string, string>;
|
|
35
|
+
tags?: string[];
|
|
36
|
+
},
|
|
37
|
+
fn: () => T,
|
|
38
|
+
): T;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
declare module "@langfuse/client" {
|
|
42
|
+
export class LangfuseClient {
|
|
43
|
+
constructor(options: {
|
|
44
|
+
publicKey: string;
|
|
45
|
+
secretKey: string;
|
|
46
|
+
baseUrl: string;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|