@juspay/neurolink 13.4.10 → 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 +2 -3
- package/README.md +3 -2
- 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 +466 -466
- package/dist/cli/commands/decide.js +25 -5
- 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/factories/providerDescriptors.d.ts +4 -3
- package/dist/factories/providerDescriptors.js +6 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp/externalServerManager.js +6 -2
- package/dist/mcp/toolRegistry.js +3 -0
- package/dist/neurolink.d.ts +20 -10
- package/dist/neurolink.js +134 -65
- 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/catalog/provider-catalog.schema.json +64 -3
- package/dist/providers/catalog/schema.js +81 -1
- package/dist/providers/catalog/xor.json +30 -10
- package/dist/providers/configuredDecision.d.ts +8 -1
- package/dist/providers/configuredDecision.js +22 -0
- package/dist/providers/decide/dialects/openaiDecisions.js +8 -0
- package/dist/providers/decide/dialects/systemOne.js +28 -2
- package/dist/providers/decide/guards.d.ts +6 -0
- package/dist/providers/decide/guards.js +22 -0
- 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/providers/systemOneDecision.d.ts +30 -7
- package/dist/providers/systemOneDecision.js +71 -14
- 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/cli.d.ts +2 -0
- package/dist/types/decision.d.ts +117 -10
- 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/providerCatalog.d.ts +12 -1
- package/dist/types/providers.d.ts +2 -0
- package/dist/types/proxy.d.ts +2 -0
- package/dist/types/span.d.ts +26 -0
- package/dist/utils/decisionAnswers.d.ts +7 -1
- package/dist/utils/decisionAnswers.js +43 -2
- package/dist/utils/decisionLimits.d.ts +13 -1
- package/dist/utils/decisionLimits.js +52 -1
- package/dist/utils/decisionMedia.d.ts +4 -2
- package/dist/utils/decisionMedia.js +216 -14
- 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 +56 -48
- 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/cli.d.ts
CHANGED
|
@@ -1312,6 +1312,8 @@ export type CliDecideArgs = {
|
|
|
1312
1312
|
image?: string[];
|
|
1313
1313
|
/** One video file (or data: URL) for a provider that reads video. */
|
|
1314
1314
|
video?: string;
|
|
1315
|
+
/** One audio file (or data: URL) for a provider that reads audio. */
|
|
1316
|
+
audio?: string;
|
|
1315
1317
|
provider?: string;
|
|
1316
1318
|
model?: string;
|
|
1317
1319
|
timeout?: number;
|
package/dist/types/decision.d.ts
CHANGED
|
@@ -53,6 +53,13 @@ export type DecisionChoiceQuestion = {
|
|
|
53
53
|
type: "choice";
|
|
54
54
|
instructions: DecisionInput;
|
|
55
55
|
criteria: Readonly<Record<string, DecisionInput | null>>;
|
|
56
|
+
/**
|
|
57
|
+
* True adds an option named `unknown` the model picks when none of the
|
|
58
|
+
* criteria fits; the answer then carries `unknown: true`. Only a provider
|
|
59
|
+
* whose `decisionLimits.questionTypes` lists `"choice-unknown"` accepts it,
|
|
60
|
+
* and no criteria key may be named `unknown` alongside it.
|
|
61
|
+
*/
|
|
62
|
+
unknown?: boolean;
|
|
56
63
|
};
|
|
57
64
|
/**
|
|
58
65
|
* Rate against an ordered rubric. The answer is the **0-based index**, so a
|
|
@@ -63,7 +70,24 @@ export type DecisionScoreQuestion = {
|
|
|
63
70
|
instructions: DecisionInput;
|
|
64
71
|
criteria: readonly (DecisionInput | null)[];
|
|
65
72
|
};
|
|
66
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Extract one typed field from the state: an amount, a reference, a name. Only
|
|
75
|
+
* a provider whose `decisionLimits.questionTypes` lists `"value"` accepts it.
|
|
76
|
+
*/
|
|
77
|
+
export type DecisionValueQuestion = {
|
|
78
|
+
type: "value";
|
|
79
|
+
instructions: DecisionInput;
|
|
80
|
+
/** The type of the extracted value. Omitted means `string`. */
|
|
81
|
+
dtype?: "string" | "int" | "float";
|
|
82
|
+
/** A regular expression the extracted text must match. */
|
|
83
|
+
pattern?: string;
|
|
84
|
+
};
|
|
85
|
+
export type DecisionQuestion = DecisionBooleanQuestion | DecisionChoiceQuestion | DecisionScoreQuestion | DecisionValueQuestion;
|
|
86
|
+
/**
|
|
87
|
+
* What a provider may be asked, per question. `"choice-unknown"` is a `choice`
|
|
88
|
+
* question that sets `unknown: true`.
|
|
89
|
+
*/
|
|
90
|
+
export type DecisionQuestionType = DecisionQuestion["type"] | "choice-unknown";
|
|
67
91
|
/** Questions keyed by an id you choose; answers return under the same ids. */
|
|
68
92
|
export type DecisionQuestionMap = Readonly<Record<string, DecisionQuestion>>;
|
|
69
93
|
export type DecisionBooleanAnswer = {
|
|
@@ -79,24 +103,34 @@ export type DecisionChoiceAnswer = {
|
|
|
79
103
|
probabilities: Readonly<Record<string, number>>;
|
|
80
104
|
/** Calibrated certainty, 0–1, derived from the distribution. */
|
|
81
105
|
confidence: number;
|
|
106
|
+
/** True when the question set `unknown` and the model picked it. */
|
|
107
|
+
unknown?: boolean;
|
|
82
108
|
};
|
|
83
109
|
export type DecisionScoreAnswer = {
|
|
84
110
|
type: "score";
|
|
85
111
|
/** Probability-weighted level index; lands between levels. */
|
|
86
112
|
score: number;
|
|
87
|
-
/** Level index (as a string key) → the description supplied. */
|
|
113
|
+
/** Level index (as a string key) → the description supplied; a level that was not a string is given as its JSON text. */
|
|
88
114
|
legend: Readonly<Record<string, string>>;
|
|
89
115
|
/** Level index (as a string key) → probability. */
|
|
90
116
|
probabilities: Readonly<Record<string, number>>;
|
|
91
117
|
confidence: number;
|
|
92
118
|
};
|
|
93
|
-
export type
|
|
119
|
+
export type DecisionValueAnswer = {
|
|
120
|
+
type: "value";
|
|
121
|
+
/** The extracted value: a number for `int` / `float`, else a string. Null when the model abstained. */
|
|
122
|
+
value: string | number | null;
|
|
123
|
+
confidence: number;
|
|
124
|
+
/** True when the model found nothing to extract; `value` is then null. */
|
|
125
|
+
unknown?: boolean;
|
|
126
|
+
};
|
|
127
|
+
export type DecisionAnswer = DecisionBooleanAnswer | DecisionChoiceAnswer | DecisionScoreAnswer | DecisionValueAnswer;
|
|
94
128
|
export type DecisionAnswerMap = Readonly<Record<string, DecisionAnswer>>;
|
|
95
129
|
export type DecisionUsage = {
|
|
96
130
|
inputTokens: number;
|
|
97
131
|
outputTokens: number;
|
|
98
132
|
};
|
|
99
|
-
/** An image or
|
|
133
|
+
/** An image, video or audio clip as the caller supplies it: raw bytes, a file path, or a data URL. */
|
|
100
134
|
export type DecisionMediaSource = Buffer | string;
|
|
101
135
|
export type DecisionRequest = {
|
|
102
136
|
state: DecisionState;
|
|
@@ -109,6 +143,11 @@ export type DecisionRequest = {
|
|
|
109
143
|
images?: readonly DecisionMediaSource[];
|
|
110
144
|
/** One video, in the same forms. Sending images as well is allowed. */
|
|
111
145
|
video?: DecisionMediaSource;
|
|
146
|
+
/**
|
|
147
|
+
* One audio clip, in the same forms (a `data:audio/…;base64,` URL). Only a
|
|
148
|
+
* provider whose `decisionLimits.media.audio` is set accepts it.
|
|
149
|
+
*/
|
|
150
|
+
audio?: DecisionMediaSource;
|
|
112
151
|
/** Overrides the provider's configured model for this call only. */
|
|
113
152
|
model?: string;
|
|
114
153
|
signal?: AbortSignal;
|
|
@@ -127,7 +166,7 @@ export type DecisionResult = {
|
|
|
127
166
|
latencyMs: number;
|
|
128
167
|
/** Server-side time behind the edge; isolates model time from network. */
|
|
129
168
|
upstreamMs?: number;
|
|
130
|
-
/** Encoded size of the images and
|
|
169
|
+
/** Encoded size of the images, video and audio sent. Absent for a text-only request. */
|
|
131
170
|
mediaBytes?: number;
|
|
132
171
|
};
|
|
133
172
|
/**
|
|
@@ -147,6 +186,16 @@ export type DecisionLimits = {
|
|
|
147
186
|
maxStateTokens: number;
|
|
148
187
|
/** Absent when the provider has no cap on questions per request. */
|
|
149
188
|
maxQuestions?: number;
|
|
189
|
+
/**
|
|
190
|
+
* The question types the provider reads. Absent means `boolean`, `choice`
|
|
191
|
+
* and `score`; a request asking anything else is refused before any network
|
|
192
|
+
* call, whether or not the limits are advisory.
|
|
193
|
+
*/
|
|
194
|
+
questionTypes?: readonly DecisionQuestionType[];
|
|
195
|
+
/** Most levels one `score` question may have. Absent means no local cap. */
|
|
196
|
+
maxScoreLevels?: number;
|
|
197
|
+
/** Most options one `choice` question may have. Absent means no local cap. */
|
|
198
|
+
maxChoiceOptions?: number;
|
|
150
199
|
/**
|
|
151
200
|
* Tokens charged per non-ASCII character. The default estimate assumes ~4
|
|
152
201
|
* characters per token, which holds for English and is several times too
|
|
@@ -208,9 +257,15 @@ export type DecisionLimitsReading = {
|
|
|
208
257
|
maxStateTokens: number;
|
|
209
258
|
/**
|
|
210
259
|
* Absent when the provider caps a request by tokens (or bytes) rather
|
|
211
|
-
* than by question count — TypeSafe
|
|
260
|
+
* than by question count — TypeSafe; `Infinity` is never used.
|
|
212
261
|
*/
|
|
213
262
|
maxQuestions?: number;
|
|
263
|
+
/** Present only when the descriptor declares it; absent means `boolean`, `choice` and `score`. */
|
|
264
|
+
questionTypes?: readonly DecisionQuestionType[];
|
|
265
|
+
/** Most levels one `score` question may have; absent means no local cap. */
|
|
266
|
+
maxScoreLevels?: number;
|
|
267
|
+
/** Most options one `choice` question may have; absent means no local cap. */
|
|
268
|
+
maxChoiceOptions?: number;
|
|
214
269
|
nonAsciiTokensPerChar?: number;
|
|
215
270
|
/** Tokens charged per ASCII digit; see {@link DecisionLimits.digitTokensPerChar}. */
|
|
216
271
|
digitTokensPerChar?: number;
|
|
@@ -241,19 +296,36 @@ export type DecisionMediaLimits = {
|
|
|
241
296
|
video: boolean;
|
|
242
297
|
/** Ceiling on the encoded request body, in bytes. */
|
|
243
298
|
maxRequestBytes: number;
|
|
299
|
+
/** Whether one audio clip is accepted, and how much of it the model hears. Absent means no audio. */
|
|
300
|
+
audio?: DecisionAudioLimits;
|
|
301
|
+
};
|
|
302
|
+
export type DecisionAudioLimits = {
|
|
303
|
+
/**
|
|
304
|
+
* Seconds of audio the model reads. A clip whose length can be read from its
|
|
305
|
+
* header (WAV, FLAC, Ogg) and runs longer is refused, since the rest would be cut
|
|
306
|
+
* off without a word.
|
|
307
|
+
*/
|
|
308
|
+
maxSeconds: number;
|
|
244
309
|
};
|
|
245
310
|
/** An image's size in pixels, read from its header. */
|
|
246
311
|
export type DecisionImageDimensions = {
|
|
247
312
|
width: number;
|
|
248
313
|
height: number;
|
|
249
314
|
};
|
|
250
|
-
/** Media after preparation:
|
|
315
|
+
/** Media after preparation: images and video are `data:` URLs, ready for the wire. */
|
|
251
316
|
export type DecisionPreparedMedia = {
|
|
252
317
|
images: string[];
|
|
253
318
|
video?: string;
|
|
254
|
-
|
|
319
|
+
audio?: DecisionPreparedAudio;
|
|
320
|
+
/** Encoded size of everything above. */
|
|
255
321
|
bytes: number;
|
|
256
322
|
};
|
|
323
|
+
/** An audio clip as the wire takes it: raw base64 and the container it was sniffed as. */
|
|
324
|
+
export type DecisionPreparedAudio = {
|
|
325
|
+
data: string;
|
|
326
|
+
format: DecisionAudioFormat;
|
|
327
|
+
};
|
|
328
|
+
export type DecisionAudioFormat = "wav" | "flac" | "ogg" | "mp3";
|
|
257
329
|
/**
|
|
258
330
|
* Discriminated by a string literal, not a boolean: the package is also
|
|
259
331
|
* compiled without strictNullChecks, where a boolean discriminant does not
|
|
@@ -266,8 +338,8 @@ export type DecisionMediaResult = {
|
|
|
266
338
|
status: "refused";
|
|
267
339
|
message: string;
|
|
268
340
|
};
|
|
269
|
-
export type DecisionMediaKind = "image" | "video";
|
|
270
|
-
/** One image or
|
|
341
|
+
export type DecisionMediaKind = "image" | "video" | "audio";
|
|
342
|
+
/** One image, video or audio clip turned into a data URL, or the reason it could not be. Same literal-discriminant rule as above. */
|
|
271
343
|
export type DecisionMediaConversion = {
|
|
272
344
|
status: "ok";
|
|
273
345
|
dataUrl: string;
|
|
@@ -283,6 +355,21 @@ export type DecisionMediaFileRead = {
|
|
|
283
355
|
status: "error";
|
|
284
356
|
message: string;
|
|
285
357
|
};
|
|
358
|
+
/**
|
|
359
|
+
* A caller's media source resolved for one kind: bytes to identify (a Buffer
|
|
360
|
+
* or a file read from disk), a `data:` URL of that kind as given, or the reason
|
|
361
|
+
* it is refused.
|
|
362
|
+
*/
|
|
363
|
+
export type DecisionMediaSourceRead = {
|
|
364
|
+
status: "buffer";
|
|
365
|
+
buffer: Buffer;
|
|
366
|
+
} | {
|
|
367
|
+
status: "dataUrl";
|
|
368
|
+
dataUrl: string;
|
|
369
|
+
} | {
|
|
370
|
+
status: "error";
|
|
371
|
+
message: string;
|
|
372
|
+
};
|
|
286
373
|
/**
|
|
287
374
|
* Why a decision call failed, normalised across vendors. TypeSafe alone
|
|
288
375
|
* returns two different error envelopes, so a provider must flatten them.
|
|
@@ -318,6 +405,11 @@ export type DecisionChoiceReading = {
|
|
|
318
405
|
name: string;
|
|
319
406
|
probability: number;
|
|
320
407
|
}[];
|
|
408
|
+
/**
|
|
409
|
+
* True when the question set `unknown` and the model picked it: `choice` is
|
|
410
|
+
* then `"unknown"`, which is none of the question's own options.
|
|
411
|
+
*/
|
|
412
|
+
unknown: boolean;
|
|
321
413
|
};
|
|
322
414
|
export type DecisionScoreReading = {
|
|
323
415
|
score: number;
|
|
@@ -325,6 +417,12 @@ export type DecisionScoreReading = {
|
|
|
325
417
|
legend: Readonly<Record<string, string>>;
|
|
326
418
|
probabilities: Readonly<Record<string, number>>;
|
|
327
419
|
};
|
|
420
|
+
export type DecisionValueReading = {
|
|
421
|
+
value: string | number | null;
|
|
422
|
+
confidence: number;
|
|
423
|
+
/** True when the model abstained; `value` is then null. */
|
|
424
|
+
unknown: boolean;
|
|
425
|
+
};
|
|
328
426
|
/**
|
|
329
427
|
* What `NeuroLink.decide()` accepts: a decision request plus the usual
|
|
330
428
|
* provider/credential selection every inference type shares.
|
|
@@ -543,6 +641,8 @@ export type DecideMedia = {
|
|
|
543
641
|
imagesKey: string;
|
|
544
642
|
/** Written only when the request carries a video; required exactly when `decisionLimits.media.video` is true. */
|
|
545
643
|
videoKey?: string;
|
|
644
|
+
/** Written only when the request carries audio, as `{ data, format }`; required exactly when `decisionLimits.media.audio` is set. */
|
|
645
|
+
audioKey?: string;
|
|
546
646
|
};
|
|
547
647
|
/**
|
|
548
648
|
* Says when a decide provider's key may be used as the default decision
|
|
@@ -580,6 +680,13 @@ export type DecideAmbientKeyCredentialField = {
|
|
|
580
680
|
/** The field in that slice. Only `baseURL` is read today. */
|
|
581
681
|
field: "baseURL";
|
|
582
682
|
};
|
|
683
|
+
/** See `DecideBlock.capableModel`. */
|
|
684
|
+
export type DecideCapableModel = {
|
|
685
|
+
/** A key of the entry's `models.catalog`. */
|
|
686
|
+
model: string;
|
|
687
|
+
/** Question types that send a request to `model`; media always does. */
|
|
688
|
+
questionTypes: readonly DecisionQuestionType[];
|
|
689
|
+
};
|
|
583
690
|
/** What a dialect lays out as one request body. */
|
|
584
691
|
export type DecisionDialectBody = {
|
|
585
692
|
readonly state: DecisionState;
|