@juspay/neurolink 13.5.0 → 13.5.1
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/CHANGELOG.md +3 -3
- package/dist/adapters/video/videoAnalyzer.d.ts +1 -0
- package/dist/adapters/video/videoAnalyzer.js +4 -0
- package/dist/autoresearch/index.d.ts +1 -0
- package/dist/autoresearch/index.js +4 -0
- package/dist/autoresearch/worker.js +4 -0
- package/dist/browser/neurolink.min.js +467 -467
- package/dist/cli/commands/observability.js +11 -4
- package/dist/cli/commands/telemetry.js +36 -6
- package/dist/cli/utils/formatters.d.ts +17 -0
- package/dist/cli/utils/formatters.js +39 -0
- package/dist/constants/langfuse.d.ts +17 -1
- package/dist/constants/langfuse.js +23 -1
- package/dist/constants/telemetry.d.ts +6 -0
- package/dist/constants/telemetry.js +6 -0
- package/dist/core/baseProvider.js +2 -0
- package/dist/core/geminiLoopAdapter.js +19 -0
- package/dist/core/loopEngine.js +10 -7
- package/dist/core/modules/StreamHandler.js +5 -4
- package/dist/core/modules/TelemetryHandler.d.ts +5 -1
- package/dist/core/modules/TelemetryHandler.js +16 -0
- package/dist/core/modules/ToolsManager.js +3 -0
- package/dist/core/nativeGenerateLoop.js +1 -1
- package/dist/evaluation/index.d.ts +1 -0
- package/dist/evaluation/index.js +4 -0
- package/dist/evaluation/ragasEvaluator.js +1 -0
- package/dist/mcp/externalServerManager.js +6 -2
- package/dist/mcp/toolRegistry.js +3 -0
- package/dist/neurolink.d.ts +16 -8
- package/dist/neurolink.js +115 -61
- package/dist/observability/FEATURE-STATUS.md +0 -4
- package/dist/observability/exporterRegistry.d.ts +6 -1
- package/dist/observability/exporterRegistry.js +18 -0
- package/dist/observability/exporterSpanProcessor.d.ts +20 -6
- package/dist/observability/exporterSpanProcessor.js +166 -34
- package/dist/observability/exporters/baseExporter.d.ts +22 -3
- package/dist/observability/exporters/baseExporter.js +87 -5
- package/dist/observability/exporters/langfuseExporter.d.ts +29 -3
- package/dist/observability/exporters/langfuseExporter.js +251 -41
- package/dist/observability/langfuseMasking.d.ts +1 -1
- package/dist/observability/langfuseMasking.js +1 -1
- package/dist/observability/otlpEncoding.d.ts +18 -5
- package/dist/observability/otlpEncoding.js +69 -12
- package/dist/observability/utils/spanSerializer.d.ts +3 -2
- package/dist/observability/utils/spanSerializer.js +5 -3
- package/dist/processors/base/BaseFileProcessor.d.ts +1 -0
- package/dist/processors/base/BaseFileProcessor.js +4 -0
- package/dist/processors/index.d.ts +1 -0
- package/dist/processors/index.js +4 -0
- package/dist/processors/registry/ProcessorRegistry.d.ts +1 -0
- package/dist/processors/registry/ProcessorRegistry.js +5 -0
- package/dist/providers/amazonBedrock/client.js +7 -5
- package/dist/providers/amazonSagemaker.js +32 -12
- package/dist/providers/anthropic/client.js +1 -0
- package/dist/providers/anthropic/loopAdapter.js +7 -3
- package/dist/providers/googleAiStudio/client.js +2 -0
- package/dist/providers/googleVertex/client.d.ts +6 -5
- package/dist/providers/googleVertex/client.js +46 -19
- package/dist/providers/openaiChatCompletionsBase.js +4 -4
- package/dist/proxy/codexUsage.js +59 -2
- package/dist/proxy/proxyTracer.d.ts +25 -1
- package/dist/proxy/proxyTracer.js +146 -22
- package/dist/proxy/proxyTranslationEngine.js +4 -2
- package/dist/proxy/sseInterceptor.js +6 -4
- package/dist/rag/chunkers/BaseChunker.js +1 -0
- package/dist/rag/index.d.ts +1 -0
- package/dist/rag/index.js +4 -0
- package/dist/rag/ragIntegration.js +1 -0
- package/dist/rag/reranker/reranker.js +2 -0
- package/dist/rag/retrieval/vectorQueryTool.js +1 -0
- package/dist/server/routes/codexProxyRoutes.js +3 -1
- package/dist/server/utils/validation.d.ts +3 -3
- package/dist/services/server/ai/observability/instrumentation.d.ts +8 -7
- package/dist/services/server/ai/observability/instrumentation.js +217 -47
- package/dist/services/server/ai/observability/langfuseSetup.d.ts +19 -1
- package/dist/services/server/ai/observability/langfuseSetup.js +62 -4
- package/dist/services/server/ai/observability/otlpSetup.d.ts +12 -2
- package/dist/services/server/ai/observability/otlpSetup.js +55 -4
- package/dist/telemetry/aiMetrics.d.ts +56 -0
- package/dist/telemetry/aiMetrics.js +229 -0
- package/dist/telemetry/attributes.d.ts +24 -1
- package/dist/telemetry/attributes.js +94 -9
- package/dist/telemetry/chatMessages.d.ts +6 -0
- package/dist/telemetry/chatMessages.js +37 -0
- package/dist/telemetry/index.d.ts +1 -1
- package/dist/telemetry/index.js +1 -1
- package/dist/telemetry/observation.d.ts +5 -5
- package/dist/telemetry/observation.js +128 -39
- package/dist/telemetry/spanSanitizer.d.ts +2 -2
- package/dist/telemetry/spanSanitizer.js +76 -8
- package/dist/telemetry/telemetryStarter.d.ts +16 -0
- package/dist/telemetry/telemetryStarter.js +28 -0
- package/dist/telemetry/traceContext.d.ts +3 -3
- package/dist/telemetry/traceContext.js +3 -3
- package/dist/telemetry/tracers.d.ts +13 -1
- package/dist/telemetry/tracers.js +49 -10
- package/dist/telemetry/withSpan.d.ts +19 -3
- package/dist/telemetry/withSpan.js +149 -20
- package/dist/types/exporter.d.ts +98 -3
- package/dist/types/livekit.d.ts +16 -1
- package/dist/types/loopEngine.d.ts +16 -1
- package/dist/types/observability.d.ts +38 -5
- package/dist/types/proxy.d.ts +2 -0
- package/dist/types/span.d.ts +26 -0
- package/dist/utils/timeout.js +4 -2
- package/dist/voice/livekit/realtimeMcpTools.js +11 -2
- package/dist/voice/livekit/realtimeMemory.d.ts +20 -2
- package/dist/voice/livekit/realtimeMemory.js +139 -46
- package/dist/voice/livekit/realtimeVoiceAgent.js +20 -8
- package/dist/voice/livekit/turnRecorder.js +22 -9
- package/dist/workflow/core/ensembleExecutor.js +2 -0
- package/dist/workflow/core/judgeScorer.js +1 -0
- package/dist/workflow/core/responseConditioner.js +1 -0
- package/dist/workflow/core/workflowRunner.js +6 -1
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.js +4 -0
- package/docs-site/static/search-index.json +32 -27
- package/package.json +21 -2
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { type Span } from "@opentelemetry/api";
|
|
2
|
-
import type { GenerationRecord, SpanOptions } from "../types/index.js";
|
|
2
|
+
import type { GenerationOperation, GenerationRecord, SpanOptions } from "../types/index.js";
|
|
3
|
+
export declare function markFailure(span: Span, error: unknown, expected?: boolean): void;
|
|
4
|
+
/**
|
|
5
|
+
* @description Ends `span` at WARNING once `stream` is garbage collected while the span is still open, for a stream result whose caller dropped it without reading it to the end or closing it. Best effort: it runs only if and when the collector reclaims `stream`, and a span that already ended is left alone.
|
|
6
|
+
* @param stream {object} - The iterable handed to the caller; `span` must not keep it reachable.
|
|
7
|
+
* @param span {Span} - Span that reading or closing `stream` would have ended.
|
|
8
|
+
* @returns {void} Nothing.
|
|
9
|
+
*/
|
|
10
|
+
export declare function endSpanWhenDropped(stream: object, span: Span): void;
|
|
3
11
|
export declare function withSpan<T>(options: SpanOptions, fn: (span: Span) => Promise<T>): Promise<T>;
|
|
4
12
|
export declare function withClientSpan<T>(options: Omit<SpanOptions, "kind">, fn: (span: Span) => Promise<T>): Promise<T>;
|
|
5
13
|
/**
|
|
@@ -40,9 +48,15 @@ export declare function withStepSpan<T>(stepNumber: number, fn: () => Promise<T>
|
|
|
40
48
|
* @description Groups the observations of each agentic loop step under one `step` span. Call `begin` at the top of a step, run the step's model call and tool dispatch through `run`, and `end` when the loop is over; `begin` closes the previous step.
|
|
41
49
|
*/
|
|
42
50
|
export declare class StepSpans {
|
|
51
|
+
private readonly operation?;
|
|
43
52
|
private current;
|
|
53
|
+
private root;
|
|
54
|
+
/**
|
|
55
|
+
* @param operation {GenerationOperation} - Public API the loop serves, naming the root opened when no span is active; inferred from the enclosing span when unset, `generate` when there is none.
|
|
56
|
+
*/
|
|
57
|
+
constructor(operation?: GenerationOperation | undefined);
|
|
44
58
|
/**
|
|
45
|
-
* @description Closes the previous step and opens `step` under the active span.
|
|
59
|
+
* @description Closes the previous step and opens `step` under the active span. When no span is active, the first step also opens a `generate` or `stream` root, so a loop run outside NeuroLink and outside any host span stays in one trace instead of starting a trace per step.
|
|
46
60
|
* @param stepNumber {number} - One-based step number within the turn.
|
|
47
61
|
* @returns {void} Nothing.
|
|
48
62
|
*/
|
|
@@ -54,8 +68,10 @@ export declare class StepSpans {
|
|
|
54
68
|
*/
|
|
55
69
|
run<T>(fn: () => T): T;
|
|
56
70
|
/**
|
|
57
|
-
* @description Closes the open step,
|
|
71
|
+
* @description Closes the open step, and the root when this loop opened one.
|
|
58
72
|
* @returns {void} Nothing.
|
|
59
73
|
*/
|
|
60
74
|
end(): void;
|
|
75
|
+
private endStep;
|
|
76
|
+
private startOrphanedRoot;
|
|
61
77
|
}
|
|
@@ -1,12 +1,40 @@
|
|
|
1
1
|
import { LangfuseOtelSpanAttributes } from "@langfuse/tracing";
|
|
2
|
-
import { context, SpanKind, SpanStatusCode, trace, } from "@opentelemetry/api";
|
|
2
|
+
import { context, SpanKind, SpanStatusCode, isSpanContextValid, trace, } from "@opentelemetry/api";
|
|
3
3
|
import { isAbortError } from "../utils/errorHandling.js";
|
|
4
4
|
import { observe, observeGeneration } from "./observation.js";
|
|
5
5
|
import { generationName, stepSpanName } from "./observationNames.js";
|
|
6
|
-
import { tracers } from "./tracers.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
import { markTurnlessRoot, tracers } from "./tracers.js";
|
|
7
|
+
// The thrown value is the caller's, and reading it can throw as well (a
|
|
8
|
+
// Proxy, a getter or toString that throws). Failure recording reads it through
|
|
9
|
+
// these, and whatever it still cannot record is skipped, so the caller always
|
|
10
|
+
// rethrows its own error.
|
|
11
|
+
function failureText(error) {
|
|
12
|
+
try {
|
|
13
|
+
return String(error instanceof Error ? error.message : error);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return "unreadable error";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function readsAsAbort(error) {
|
|
20
|
+
try {
|
|
21
|
+
return isAbortError(error);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function markFailure(span, error, expected = false) {
|
|
28
|
+
try {
|
|
29
|
+
recordFailure(span, error, expected);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// The span keeps whatever was recorded before the value could not be read.
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function recordFailure(span, error, expected) {
|
|
36
|
+
const message = failureText(error);
|
|
37
|
+
if (readsAsAbort(error)) {
|
|
10
38
|
span.setAttributes({
|
|
11
39
|
[LangfuseOtelSpanAttributes.OBSERVATION_LEVEL]: "WARNING",
|
|
12
40
|
[LangfuseOtelSpanAttributes.OBSERVATION_STATUS_MESSAGE]: message,
|
|
@@ -24,9 +52,50 @@ function markFailure(span, error, expected = false) {
|
|
|
24
52
|
span.recordException(error);
|
|
25
53
|
}
|
|
26
54
|
}
|
|
55
|
+
// A stream result its caller drops without reading it to the end or closing
|
|
56
|
+
// it can no longer end its span, so the span is ended here once the result is
|
|
57
|
+
// garbage collected. Best effort: collection may come late or never.
|
|
58
|
+
const droppedStreams = new FinalizationRegistry((span) => {
|
|
59
|
+
try {
|
|
60
|
+
if (span.isRecording()) {
|
|
61
|
+
span.setAttributes({
|
|
62
|
+
[LangfuseOtelSpanAttributes.OBSERVATION_LEVEL]: "WARNING",
|
|
63
|
+
[LangfuseOtelSpanAttributes.OBSERVATION_STATUS_MESSAGE]: "stream dropped before it was read to the end",
|
|
64
|
+
});
|
|
65
|
+
span.end();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// A finalizer has no caller to report to.
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
/**
|
|
73
|
+
* @description Ends `span` at WARNING once `stream` is garbage collected while the span is still open, for a stream result whose caller dropped it without reading it to the end or closing it. Best effort: it runs only if and when the collector reclaims `stream`, and a span that already ended is left alone.
|
|
74
|
+
* @param stream {object} - The iterable handed to the caller; `span` must not keep it reachable.
|
|
75
|
+
* @param span {Span} - Span that reading or closing `stream` would have ended.
|
|
76
|
+
* @returns {void} Nothing.
|
|
77
|
+
*/
|
|
78
|
+
export function endSpanWhenDropped(stream, span) {
|
|
79
|
+
droppedStreams.register(stream, span);
|
|
80
|
+
}
|
|
81
|
+
function startsOrphanedRoot(options) {
|
|
82
|
+
if (!options.detached || !options.rootWhenOrphaned) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
const active = trace.getSpan(context.active());
|
|
86
|
+
return !active || !isSpanContextValid(active.spanContext());
|
|
87
|
+
}
|
|
27
88
|
export async function withSpan(options, fn) {
|
|
28
|
-
const { name, tracer, kind = SpanKind.INTERNAL, attributes, detached, } = options;
|
|
89
|
+
const { name, tracer, kind = SpanKind.INTERNAL, attributes, detached, observationType, } = options;
|
|
90
|
+
const asRoot = startsOrphanedRoot(options);
|
|
29
91
|
const run = async (span) => {
|
|
92
|
+
if (asRoot) {
|
|
93
|
+
markTurnlessRoot(span);
|
|
94
|
+
observe(span, "agent", {});
|
|
95
|
+
}
|
|
96
|
+
else if (observationType) {
|
|
97
|
+
observe(span, observationType, {});
|
|
98
|
+
}
|
|
30
99
|
if (attributes) {
|
|
31
100
|
for (const [key, value] of Object.entries(attributes)) {
|
|
32
101
|
if (value !== undefined) {
|
|
@@ -47,7 +116,7 @@ export async function withSpan(options, fn) {
|
|
|
47
116
|
span.end();
|
|
48
117
|
}
|
|
49
118
|
};
|
|
50
|
-
return detached
|
|
119
|
+
return detached && !asRoot
|
|
51
120
|
? run(tracer.startSpan(name, { kind }))
|
|
52
121
|
: tracer.startActiveSpan(name, { kind }, run);
|
|
53
122
|
}
|
|
@@ -72,8 +141,16 @@ export async function withClientSpan(options, fn) {
|
|
|
72
141
|
* ```
|
|
73
142
|
*/
|
|
74
143
|
export async function withStreamSpan(options, fn, getIterable, setIterable) {
|
|
75
|
-
const { name, tracer, kind = SpanKind.CLIENT, attributes, detached, } = options;
|
|
144
|
+
const { name, tracer, kind = SpanKind.CLIENT, attributes, detached, observationType, } = options;
|
|
145
|
+
const asRoot = startsOrphanedRoot(options);
|
|
76
146
|
const span = tracer.startSpan(name, { kind });
|
|
147
|
+
if (asRoot) {
|
|
148
|
+
markTurnlessRoot(span);
|
|
149
|
+
observe(span, "agent", {});
|
|
150
|
+
}
|
|
151
|
+
else if (observationType) {
|
|
152
|
+
observe(span, observationType, {});
|
|
153
|
+
}
|
|
77
154
|
if (attributes) {
|
|
78
155
|
for (const [key, value] of Object.entries(attributes)) {
|
|
79
156
|
if (value !== undefined) {
|
|
@@ -81,7 +158,7 @@ export async function withStreamSpan(options, fn, getIterable, setIterable) {
|
|
|
81
158
|
}
|
|
82
159
|
}
|
|
83
160
|
}
|
|
84
|
-
const spanContext = detached
|
|
161
|
+
const spanContext = detached && !asRoot
|
|
85
162
|
? context.active()
|
|
86
163
|
: trace.setSpan(context.active(), span);
|
|
87
164
|
let result;
|
|
@@ -93,7 +170,15 @@ export async function withStreamSpan(options, fn, getIterable, setIterable) {
|
|
|
93
170
|
span.end();
|
|
94
171
|
throw error;
|
|
95
172
|
}
|
|
96
|
-
|
|
173
|
+
let iterator;
|
|
174
|
+
try {
|
|
175
|
+
iterator = getIterable(result)[Symbol.asyncIterator]();
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
markFailure(span, error);
|
|
179
|
+
span.end();
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
97
182
|
let ended = false;
|
|
98
183
|
let started = false;
|
|
99
184
|
function end(status) {
|
|
@@ -134,8 +219,11 @@ export async function withStreamSpan(options, fn, getIterable, setIterable) {
|
|
|
134
219
|
return step;
|
|
135
220
|
}
|
|
136
221
|
catch (err) {
|
|
137
|
-
|
|
138
|
-
|
|
222
|
+
// A return() that raced this pull has already ended the span.
|
|
223
|
+
if (!ended) {
|
|
224
|
+
markFailure(span, err);
|
|
225
|
+
end();
|
|
226
|
+
}
|
|
139
227
|
throw err;
|
|
140
228
|
}
|
|
141
229
|
},
|
|
@@ -144,13 +232,31 @@ export async function withStreamSpan(options, fn, getIterable, setIterable) {
|
|
|
144
232
|
return { done: true, value: undefined };
|
|
145
233
|
},
|
|
146
234
|
async throw(error) {
|
|
147
|
-
|
|
148
|
-
|
|
235
|
+
const forward = iterator.throw;
|
|
236
|
+
if (ended || forward === undefined) {
|
|
237
|
+
await close();
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
240
|
+
try {
|
|
241
|
+
const step = await context.with(spanContext, () => forward.call(iterator, error));
|
|
242
|
+
if (step.done) {
|
|
243
|
+
end({ code: SpanStatusCode.OK });
|
|
244
|
+
}
|
|
245
|
+
return step;
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
if (!ended) {
|
|
249
|
+
markFailure(span, err);
|
|
250
|
+
end();
|
|
251
|
+
}
|
|
252
|
+
throw err;
|
|
253
|
+
}
|
|
149
254
|
},
|
|
150
255
|
[Symbol.asyncIterator]() {
|
|
151
256
|
return wrapped;
|
|
152
257
|
},
|
|
153
258
|
};
|
|
259
|
+
endSpanWhenDropped(wrapped, span);
|
|
154
260
|
return setIterable(result, wrapped);
|
|
155
261
|
}
|
|
156
262
|
/**
|
|
@@ -189,17 +295,24 @@ export async function withStepSpan(stepNumber, fn) {
|
|
|
189
295
|
* @description Groups the observations of each agentic loop step under one `step` span. Call `begin` at the top of a step, run the step's model call and tool dispatch through `run`, and `end` when the loop is over; `begin` closes the previous step.
|
|
190
296
|
*/
|
|
191
297
|
export class StepSpans {
|
|
298
|
+
operation;
|
|
192
299
|
current;
|
|
300
|
+
root;
|
|
301
|
+
/**
|
|
302
|
+
* @param operation {GenerationOperation} - Public API the loop serves, naming the root opened when no span is active; inferred from the enclosing span when unset, `generate` when there is none.
|
|
303
|
+
*/
|
|
304
|
+
constructor(operation) {
|
|
305
|
+
this.operation = operation;
|
|
306
|
+
}
|
|
193
307
|
/**
|
|
194
|
-
* @description Closes the previous step and opens `step` under the active span.
|
|
308
|
+
* @description Closes the previous step and opens `step` under the active span. When no span is active, the first step also opens a `generate` or `stream` root, so a loop run outside NeuroLink and outside any host span stays in one trace instead of starting a trace per step.
|
|
195
309
|
* @param stepNumber {number} - One-based step number within the turn.
|
|
196
310
|
* @returns {void} Nothing.
|
|
197
311
|
*/
|
|
198
312
|
begin(stepNumber) {
|
|
199
|
-
this.
|
|
200
|
-
this.
|
|
201
|
-
|
|
202
|
-
});
|
|
313
|
+
this.endStep();
|
|
314
|
+
this.root ??= this.startOrphanedRoot();
|
|
315
|
+
this.current = tracers.sdk.startSpan(stepSpanName(), { kind: SpanKind.INTERNAL }, this.root ? trace.setSpan(context.active(), this.root) : undefined);
|
|
203
316
|
observe(this.current, "span", { metadata: { step_index: stepNumber } });
|
|
204
317
|
}
|
|
205
318
|
/**
|
|
@@ -214,11 +327,27 @@ export class StepSpans {
|
|
|
214
327
|
: fn();
|
|
215
328
|
}
|
|
216
329
|
/**
|
|
217
|
-
* @description Closes the open step,
|
|
330
|
+
* @description Closes the open step, and the root when this loop opened one.
|
|
218
331
|
* @returns {void} Nothing.
|
|
219
332
|
*/
|
|
220
333
|
end() {
|
|
334
|
+
this.endStep();
|
|
335
|
+
this.root?.end();
|
|
336
|
+
this.root = undefined;
|
|
337
|
+
}
|
|
338
|
+
endStep() {
|
|
221
339
|
this.current?.end();
|
|
222
340
|
this.current = undefined;
|
|
223
341
|
}
|
|
342
|
+
startOrphanedRoot() {
|
|
343
|
+
const active = trace.getSpan(context.active());
|
|
344
|
+
if (active && isSpanContextValid(active.spanContext())) {
|
|
345
|
+
return undefined;
|
|
346
|
+
}
|
|
347
|
+
const root = markTurnlessRoot(tracers.sdk.startSpan(generationName(this.operation), {
|
|
348
|
+
kind: SpanKind.INTERNAL,
|
|
349
|
+
}));
|
|
350
|
+
observe(root, "agent", {});
|
|
351
|
+
return root;
|
|
352
|
+
}
|
|
224
353
|
}
|
package/dist/types/exporter.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Agent as HttpAgent } from "node:http";
|
|
2
|
+
import type { Agent as HttpsAgent } from "node:https";
|
|
1
3
|
import type { JsonValue } from "./common.js";
|
|
2
4
|
import type { SpanAttributes } from "./span.js";
|
|
3
5
|
/**
|
|
@@ -54,6 +56,32 @@ export type ExporterHealthStatus = {
|
|
|
54
56
|
pendingSpans: number;
|
|
55
57
|
errors?: string[];
|
|
56
58
|
};
|
|
59
|
+
/**
|
|
60
|
+
* Point-in-time state of one registered exporter, as `getTelemetryStatus()` and
|
|
61
|
+
* the CLI status commands report it. `pendingSpans` counts spans queued and not
|
|
62
|
+
* yet handed to the network; `deliveredSpans` and `failedSpans` count what the
|
|
63
|
+
* backend accepted and what was dropped since the process started.
|
|
64
|
+
*/
|
|
65
|
+
export type ExporterStatus = {
|
|
66
|
+
name: string;
|
|
67
|
+
enabled: boolean;
|
|
68
|
+
healthy: boolean;
|
|
69
|
+
pendingSpans: number;
|
|
70
|
+
deliveredSpans: number;
|
|
71
|
+
failedSpans: number;
|
|
72
|
+
/** ISO timestamp of the last export that delivered spans */
|
|
73
|
+
lastExportTime?: string;
|
|
74
|
+
errors?: string[];
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* What an exporter has delivered and dropped, and why its latest delivery
|
|
78
|
+
* failed, as `getStatuses()` reports it.
|
|
79
|
+
*/
|
|
80
|
+
export type ExporterDeliveryCounts = {
|
|
81
|
+
delivered: number;
|
|
82
|
+
failed: number;
|
|
83
|
+
lastError: string | undefined;
|
|
84
|
+
};
|
|
57
85
|
/**
|
|
58
86
|
* Langfuse exporter configuration
|
|
59
87
|
*/
|
|
@@ -70,16 +98,24 @@ export type LangfuseExporterConfig = ExporterConfig & {
|
|
|
70
98
|
* When true, `input` and `output` fields are omitted from exported spans and
|
|
71
99
|
* generations. Enable in compliance-sensitive deployments where prompt/response
|
|
72
100
|
* content is considered PII or subject to data-minimisation requirements.
|
|
73
|
-
* Defaults to false (input/output are exported).
|
|
101
|
+
* Defaults to false (input/output are exported). It acts on what this
|
|
102
|
+
* exporter sends to Langfuse and nowhere else.
|
|
74
103
|
*/
|
|
75
104
|
redactIO?: boolean;
|
|
76
105
|
/**
|
|
77
|
-
* Applied to input, output and metadata before they are sent
|
|
78
|
-
* throws, the value is replaced by `<fully masked>`.
|
|
106
|
+
* Applied to input, output and metadata before they are sent to Langfuse.
|
|
107
|
+
* When it throws, the value is replaced by `<fully masked>`. It acts on what
|
|
108
|
+
* this exporter sends and nowhere else: not on other exporters, the OTLP
|
|
109
|
+
* export, `getSpans()` or error text.
|
|
79
110
|
*/
|
|
80
111
|
mask?: (params: {
|
|
81
112
|
data: JsonValue;
|
|
82
113
|
}) => JsonValue;
|
|
114
|
+
/**
|
|
115
|
+
* Milliseconds `flush()` and `shutdown()` wait for delivery before they
|
|
116
|
+
* give up on what is still in flight and drop it. Defaults to 3000.
|
|
117
|
+
*/
|
|
118
|
+
flushBudgetMs?: number;
|
|
83
119
|
};
|
|
84
120
|
/**
|
|
85
121
|
* LangSmith exporter configuration
|
|
@@ -285,6 +321,17 @@ export type OtlpKeyValue = {
|
|
|
285
321
|
key: string;
|
|
286
322
|
value: OtlpAnyValue;
|
|
287
323
|
};
|
|
324
|
+
/** @description How `createExporterSpanProcessor` treats the exporters of its registry. */
|
|
325
|
+
export type ExporterSpanProcessorOptions = {
|
|
326
|
+
/** Whether the processor's `shutdown()` also shuts down the registry's exporters. Defaults to `true`; `false` flushes them and leaves them running. */
|
|
327
|
+
shutdownExporters?: boolean;
|
|
328
|
+
};
|
|
329
|
+
/** @description An OTLP/JSON link from one span to another. */
|
|
330
|
+
export type OtlpLink = {
|
|
331
|
+
traceId: string;
|
|
332
|
+
spanId: string;
|
|
333
|
+
attributes: OtlpKeyValue[];
|
|
334
|
+
};
|
|
288
335
|
/** @description An OTLP/JSON span as Langfuse's ingestion endpoint reads it. */
|
|
289
336
|
export type OtlpSpan = {
|
|
290
337
|
traceId: string;
|
|
@@ -300,12 +347,60 @@ export type OtlpSpan = {
|
|
|
300
347
|
timeUnixNano: string;
|
|
301
348
|
attributes: OtlpKeyValue[];
|
|
302
349
|
}[];
|
|
350
|
+
links?: OtlpLink[];
|
|
303
351
|
status: {
|
|
304
352
|
code: number;
|
|
305
353
|
message?: string;
|
|
306
354
|
};
|
|
307
355
|
};
|
|
356
|
+
/** @description An encoded span together with the resource and instrumentation scope it was produced under. */
|
|
357
|
+
export type OtlpEncodedSpan = {
|
|
358
|
+
span: OtlpSpan;
|
|
359
|
+
resource: OtlpKeyValue[];
|
|
360
|
+
scope: {
|
|
361
|
+
name: string;
|
|
362
|
+
version?: string;
|
|
363
|
+
};
|
|
364
|
+
};
|
|
365
|
+
/** @description The spans one instrumentation scope produced, as an OTLP/JSON request groups them. */
|
|
366
|
+
export type OtlpScopeSpans = {
|
|
367
|
+
scope: {
|
|
368
|
+
name: string;
|
|
369
|
+
version?: string;
|
|
370
|
+
};
|
|
371
|
+
spans: OtlpSpan[];
|
|
372
|
+
};
|
|
373
|
+
/** @description An OTLP/JSON trace export request body. */
|
|
374
|
+
export type OtlpTraceRequest = {
|
|
375
|
+
resourceSpans: {
|
|
376
|
+
resource: {
|
|
377
|
+
attributes: OtlpKeyValue[];
|
|
378
|
+
};
|
|
379
|
+
scopeSpans: OtlpScopeSpans[];
|
|
380
|
+
}[];
|
|
381
|
+
};
|
|
382
|
+
/** @description What one delivery attempt of a batch to Langfuse achieved. */
|
|
383
|
+
export type LangfuseDeliveryReport = {
|
|
384
|
+
delivered: number;
|
|
385
|
+
rejected: number;
|
|
386
|
+
droppedIds: string[];
|
|
387
|
+
error?: string;
|
|
388
|
+
};
|
|
389
|
+
/** @description How Langfuse answered one export request: it took the spans (some perhaps rejected) or it did not take them. */
|
|
390
|
+
export type LangfusePostOutcome = {
|
|
391
|
+
accepted: true;
|
|
392
|
+
rejected: number;
|
|
393
|
+
} | {
|
|
394
|
+
accepted: false;
|
|
395
|
+
};
|
|
308
396
|
/** @description What the Langfuse exporter adds to, masks in and removes from span attributes before sending. */
|
|
309
397
|
export type LangfuseAttributePolicy = Pick<LangfuseExporterConfig, "environment" | "release" | "mask"> & {
|
|
310
398
|
redactIO: boolean;
|
|
311
399
|
};
|
|
400
|
+
/** @description The connections NeuroLink's OTLP exporters open, which a flush that has run out of its budget can close. */
|
|
401
|
+
export type OtlpConnections = {
|
|
402
|
+
/** Hands an exporter the agent it opens its connections with. */
|
|
403
|
+
agentFor: (protocol: string) => HttpAgent | HttpsAgent;
|
|
404
|
+
/** Closes every connection now, and again once a retry that was asleep at that moment has sent. */
|
|
405
|
+
cut: () => void;
|
|
406
|
+
};
|
package/dist/types/livekit.d.ts
CHANGED
|
@@ -613,16 +613,18 @@ export type VoiceTurnRecorder = {
|
|
|
613
613
|
* Call it once, when the agent is about to speak its greeting.
|
|
614
614
|
*/
|
|
615
615
|
expectGreeting: () => void;
|
|
616
|
-
/** A tool call started in the current exchange. */
|
|
616
|
+
/** A tool call started in the current exchange. `callId` pairs it with its end when calls overlap. */
|
|
617
617
|
toolStart: (call: {
|
|
618
618
|
name: string;
|
|
619
619
|
args?: unknown;
|
|
620
|
+
callId?: string;
|
|
620
621
|
}) => void;
|
|
621
622
|
/** A tool call finished in the current exchange. */
|
|
622
623
|
toolEnd: (call: {
|
|
623
624
|
name: string;
|
|
624
625
|
result?: unknown;
|
|
625
626
|
error?: string;
|
|
627
|
+
callId?: string;
|
|
626
628
|
}) => void;
|
|
627
629
|
/**
|
|
628
630
|
* Shutdown: close what is open, then wait for pending writes — but no longer
|
|
@@ -632,6 +634,15 @@ export type VoiceTurnRecorder = {
|
|
|
632
634
|
/** Counters, for logs and tests. */
|
|
633
635
|
stats: () => VoiceTurnRecorderStats;
|
|
634
636
|
};
|
|
637
|
+
/** Who and what a realtime turn is traced as; `userId` is set only for a verified binding. */
|
|
638
|
+
export type RealtimeTracedCall = {
|
|
639
|
+
sessionId?: string;
|
|
640
|
+
userId?: string;
|
|
641
|
+
roomName?: string;
|
|
642
|
+
model?: string;
|
|
643
|
+
/** The provider of the realtime backend (`vertex` for Gemini Live, `xai` for Grok Voice); `vertex` when absent. */
|
|
644
|
+
provider?: string;
|
|
645
|
+
};
|
|
635
646
|
/** What a realtime call needs from its memory once its binding verified. */
|
|
636
647
|
export type RealtimeCallMemory = {
|
|
637
648
|
recorder: VoiceTurnRecorder;
|
|
@@ -651,6 +662,8 @@ export type VoiceTurnRecorderStats = {
|
|
|
651
662
|
export type VoiceTurnRecorderOptions = {
|
|
652
663
|
/** Stores one exchange. Throwing means "not stored"; the recorder retries. */
|
|
653
664
|
write: (record: VoiceTurnRecord) => Promise<void>;
|
|
665
|
+
/** An exchange closed: called once per exchange, in order, before its write is queued, so it never waits behind earlier writes. */
|
|
666
|
+
onClosed?: (record: VoiceTurnRecord) => void;
|
|
654
667
|
/** A write succeeded. */
|
|
655
668
|
onRecorded?: (record: VoiceTurnRecord) => void;
|
|
656
669
|
/** A write failed after every retry. The call continues. */
|
|
@@ -771,11 +784,13 @@ export type BuildRealtimeMcpToolsParams = {
|
|
|
771
784
|
onToolStart?: (call: {
|
|
772
785
|
name: string;
|
|
773
786
|
args: Record<string, unknown>;
|
|
787
|
+
callId?: string;
|
|
774
788
|
}) => void;
|
|
775
789
|
/** Observes a tool call as it ends, with its result as text or its error. */
|
|
776
790
|
onToolEnd?: (call: {
|
|
777
791
|
name: string;
|
|
778
792
|
result?: string;
|
|
779
793
|
error?: string;
|
|
794
|
+
callId?: string;
|
|
780
795
|
}) => void;
|
|
781
796
|
};
|
|
@@ -3,7 +3,7 @@ import type { Span } from "@opentelemetry/api";
|
|
|
3
3
|
import type { Tool } from "./tools.js";
|
|
4
4
|
import type { GenerateStopReason } from "./generate.js";
|
|
5
5
|
import type { UnknownRecord } from "./common.js";
|
|
6
|
-
import type { GenerationRecord } from "./observability.js";
|
|
6
|
+
import type { GenerationOperation, GenerationRecord } from "./observability.js";
|
|
7
7
|
import type { CollectedChunkResult, NativeFunctionCall, NativeToolDeclarationsResult } from "./providers.js";
|
|
8
8
|
import type { ExecutionControlDecision, ExecutionControlStepContext } from "./stream.js";
|
|
9
9
|
/**
|
|
@@ -213,6 +213,15 @@ export type AgenticLoopAdapter<TConversation = unknown, TRaw = unknown> = {
|
|
|
213
213
|
*/
|
|
214
214
|
buildToolResultMessages(conversation: TConversation, stepResult: AgenticLoopStepResult<TRaw>, toolResults: AgenticLoopToolCallResult[], step: number): TConversation;
|
|
215
215
|
mapFinishReason(rawStopReason: string | undefined, hadToolCalls: boolean): string;
|
|
216
|
+
/**
|
|
217
|
+
* Optional: maps a step's usage onto what its generation observation
|
|
218
|
+
* prices, where `inputTokens` excludes cache reads and `outputTokens`
|
|
219
|
+
* includes reasoning. Only for providers whose API reports otherwise
|
|
220
|
+
* (Gemini counts cached tokens inside the prompt count and thinking tokens
|
|
221
|
+
* outside the candidate count). The turn totals the engine returns are not
|
|
222
|
+
* touched: callers already reconcile those once.
|
|
223
|
+
*/
|
|
224
|
+
observedUsage?(usage: AgenticLoopUsage): AgenticLoopUsage;
|
|
216
225
|
/** Optional: in-turn context-budget reclaim, called once per step before buildStepRequest. */
|
|
217
226
|
planReclaim?(conversation: TConversation, step: number): AgenticLoopReclaimResult<TConversation> | undefined;
|
|
218
227
|
/** Optional: Vertex+Gemini-only single-retry-on-malformed-call. */
|
|
@@ -528,6 +537,12 @@ export type AgenticLoopOptions = {
|
|
|
528
537
|
execute?: (args: Record<string, unknown>, opts: unknown) => Promise<unknown>;
|
|
529
538
|
}>;
|
|
530
539
|
abortSignal?: AbortSignal;
|
|
540
|
+
/**
|
|
541
|
+
* Public API the turn serves, used only to name the root observation the
|
|
542
|
+
* loop opens when it runs with no active span. Inferred from the enclosing
|
|
543
|
+
* span when omitted, and `generate` when there is none.
|
|
544
|
+
*/
|
|
545
|
+
operation?: GenerationOperation;
|
|
531
546
|
/**
|
|
532
547
|
* Span the per-step provider retry annotates, via
|
|
533
548
|
* `withProviderRetry(..., span, ...)` — it records
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* These configs are passed from the parent application (e.g., Lighthouse)
|
|
4
4
|
* to enable telemetry and observability features in Neurolink SDK
|
|
5
5
|
*/
|
|
6
|
-
import type { AttributeValue } from "@opentelemetry/api";
|
|
6
|
+
import type { AttributeValue, Counter, Histogram, Meter } from "@opentelemetry/api";
|
|
7
7
|
import type { JsonValue, RawUsageObject, Unknown } from "./common.js";
|
|
8
8
|
import type { SpanData } from "./span.js";
|
|
9
9
|
/**
|
|
@@ -37,20 +37,26 @@ export type LangfuseSpanAttributes = {
|
|
|
37
37
|
* @description Langfuse exporter options. Every field falls back to its `LANGFUSE_*` environment variable when omitted.
|
|
38
38
|
*/
|
|
39
39
|
export type NeurolinkLangfuseConfig = {
|
|
40
|
+
/** `false` keeps Langfuse export off although keys are present; any other value, or leaving it out, leaves it on. */
|
|
41
|
+
enabled?: boolean;
|
|
40
42
|
/** Project public key; defaults to `LANGFUSE_PUBLIC_KEY`. */
|
|
41
43
|
publicKey?: string;
|
|
42
44
|
/** Project secret key; defaults to `LANGFUSE_SECRET_KEY`. */
|
|
43
45
|
secretKey?: string;
|
|
44
46
|
/** Langfuse host; defaults to `LANGFUSE_BASE_URL`, then Langfuse Cloud. */
|
|
45
47
|
baseUrl?: string;
|
|
46
|
-
/** Environment name; defaults to `LANGFUSE_TRACING_ENVIRONMENT`. */
|
|
48
|
+
/** Environment name on Langfuse traces; defaults to `LANGFUSE_TRACING_ENVIRONMENT`. The OTLP resource's `deployment.environment` also falls back to `LANGFUSE_ENVIRONMENT`, then `PUBLIC_APP_ENVIRONMENT`. */
|
|
47
49
|
environment?: string;
|
|
48
|
-
/** Release identifier; defaults to `LANGFUSE_RELEASE`. */
|
|
50
|
+
/** Release identifier on Langfuse traces; defaults to `LANGFUSE_RELEASE`. The OTLP resource's `service.version` also falls back to `PUBLIC_APP_VERSION`. */
|
|
49
51
|
release?: string;
|
|
50
|
-
/** Applied to input, output and metadata before they
|
|
52
|
+
/** Applied to input, output and metadata before they are sent to Langfuse. It does not reach other exporters, the OTLP export, `getSpans()` or error text. */
|
|
51
53
|
mask?: (params: {
|
|
52
54
|
data: JsonValue;
|
|
53
55
|
}) => JsonValue;
|
|
56
|
+
/** Leaves input and output out of what is sent to Langfuse. It does not reach other exporters, the OTLP export, `getSpans()` or error text. */
|
|
57
|
+
redactIO?: boolean;
|
|
58
|
+
/** Milliseconds a flush or shutdown waits for the Langfuse exporter before it drops what is still in flight; defaults to 3000. */
|
|
59
|
+
flushBudgetMs?: number;
|
|
54
60
|
/** `"immediate"` sends every span as it ends; `"batched"` (default) queues them. */
|
|
55
61
|
exportMode?: "batched" | "immediate";
|
|
56
62
|
/** Spans queued before a batch is sent; defaults to 15. */
|
|
@@ -59,7 +65,26 @@ export type NeurolinkLangfuseConfig = {
|
|
|
59
65
|
flushInterval?: number;
|
|
60
66
|
};
|
|
61
67
|
/**
|
|
62
|
-
* @description
|
|
68
|
+
* @description Kind of connection counted by the `connections_total` metric.
|
|
69
|
+
*/
|
|
70
|
+
export type MetricConnectionType = "websocket" | "sse" | "http";
|
|
71
|
+
/**
|
|
72
|
+
* @description The OpenTelemetry instruments behind NeuroLink's `ai_*`, `mcp_*`, `connections_total`, `response_time_ms` and `custom_*` metrics, created on one meter.
|
|
73
|
+
*/
|
|
74
|
+
export type AiMetricInstruments = {
|
|
75
|
+
meter: Meter;
|
|
76
|
+
requests: Counter;
|
|
77
|
+
duration: Histogram;
|
|
78
|
+
tokens: Counter;
|
|
79
|
+
cost: Counter;
|
|
80
|
+
providerErrors: Counter;
|
|
81
|
+
mcpToolCalls: Counter;
|
|
82
|
+
connections: Counter;
|
|
83
|
+
responseTime: Histogram;
|
|
84
|
+
custom: Map<string, Counter | Histogram>;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* @description Observability configuration for the NeuroLink SDK. Langfuse turns on automatically when `LANGFUSE_PUBLIC_KEY` and `LANGFUSE_SECRET_KEY` are set and `LANGFUSE_ENABLED` is not `false`, `0`, `off` or `no`; `false` turns it off.
|
|
63
88
|
*/
|
|
64
89
|
export type ObservabilityConfig = {
|
|
65
90
|
/** `false` disables Langfuse, `true` or an options object enables it. */
|
|
@@ -387,12 +412,20 @@ export type HealthMetrics = {
|
|
|
387
412
|
export type SpanOptions = {
|
|
388
413
|
name: string;
|
|
389
414
|
tracer: import("@opentelemetry/api").Tracer;
|
|
415
|
+
/** Marks the span as an observation of this type when it starts, which is what sends it to the exporters. Without it a span is exported only if its own code marks it with `observe`. */
|
|
416
|
+
observationType?: ObservationType;
|
|
390
417
|
kind?: import("@opentelemetry/api").SpanKind;
|
|
391
418
|
attributes?: Record<string, string | number | boolean | undefined>;
|
|
392
419
|
/** Marks a thrown error as an expected skip whose Langfuse level the span set itself, so `withSpan` keeps it instead of raising ERROR. */
|
|
393
420
|
expectedFailure?: (error: unknown) => boolean;
|
|
394
421
|
/** Keeps the span out of the active context, so spans started inside `fn` parent to the nearest ancestor that is exported. */
|
|
395
422
|
detached?: boolean;
|
|
423
|
+
/**
|
|
424
|
+
* With `detached`, lets the span be the active, exported root of its trace
|
|
425
|
+
* when no span is active, so what it wraps stays in one trace instead of
|
|
426
|
+
* each child starting its own. With an active ancestor it stays detached.
|
|
427
|
+
*/
|
|
428
|
+
rootWhenOrphaned?: boolean;
|
|
396
429
|
};
|
|
397
430
|
/** Trace + parent span IDs used to correlate metric records with spans. */
|
|
398
431
|
export type MetricsTraceContext = {
|
package/dist/types/proxy.d.ts
CHANGED
|
@@ -2478,6 +2478,8 @@ export type CodexStreamEvidence = {
|
|
|
2478
2478
|
terminalBytes: number;
|
|
2479
2479
|
/** Malformed, oversized or undispatched frames prevent proving output absence. */
|
|
2480
2480
|
observationIncomplete?: boolean;
|
|
2481
|
+
/** Output items past the recorded-size cap were left out of `response.output`. */
|
|
2482
|
+
outputItemsOmitted?: boolean;
|
|
2481
2483
|
firstUsefulOutputAt?: number;
|
|
2482
2484
|
firstUsefulOutputEvent?: string;
|
|
2483
2485
|
errorType?: string;
|