@juspay/neurolink 13.6.3 → 13.6.5
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 -2
- package/dist/browser/neurolink.min.js +390 -390
- package/dist/core/nativeGenerateLoop.d.ts +13 -0
- package/dist/core/nativeGenerateLoop.js +38 -5
- package/dist/providers/amazonSagemaker.js +2 -12
- package/dist/providers/anthropic/client.js +2 -12
- package/dist/providers/openaiChatCompletionsBase.js +5 -23
- package/dist/telemetry/attributes.d.ts +1 -1
- package/dist/telemetry/attributes.js +4 -36
- package/dist/types/generate.d.ts +6 -5
- package/package.json +1 -1
|
@@ -86,6 +86,19 @@ export declare const hasNativeDoGenerate: (value: unknown) => value is {
|
|
|
86
86
|
};
|
|
87
87
|
/** A tool's inputSchema with its lazy (function) form, if any, resolved. */
|
|
88
88
|
export declare const resolveToolInputSchema: (schema: Tool["inputSchema"]) => Exclude<Tool["inputSchema"], (...args: never[]) => unknown>;
|
|
89
|
+
/**
|
|
90
|
+
* The provider-neutral declaration of one tool: the shape every provider's
|
|
91
|
+
* `doGenerate` already converts to its own wire format. The loop uses it for
|
|
92
|
+
* the tools discovery loads mid-turn, and the providers that run the loop use
|
|
93
|
+
* it for their initial declarations, so a tool is declared the same way
|
|
94
|
+
* whether it is there at the start or joins later.
|
|
95
|
+
*/
|
|
96
|
+
export declare const toNativeToolDeclaration: (name: string, tool: Tool) => {
|
|
97
|
+
type: "function";
|
|
98
|
+
name: string;
|
|
99
|
+
description: string;
|
|
100
|
+
inputSchema: object;
|
|
101
|
+
};
|
|
89
102
|
/**
|
|
90
103
|
* Spell a JSON Schema into the conversation's system turn.
|
|
91
104
|
*
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { observeGeneration } from "../telemetry/observation.js";
|
|
17
17
|
import { StepSpans, withGeneration } from "../telemetry/withSpan.js";
|
|
18
18
|
import { logger } from "../utils/logger.js";
|
|
19
|
+
import { convertZodToJsonSchema } from "../utils/schemaConversion.js";
|
|
19
20
|
import { guardToolExecutor } from "./toolExecutionGuards.js";
|
|
20
21
|
import { resolveLiveTool } from "../tools/toolDiscovery.js";
|
|
21
22
|
const DEFAULT_TOOL_CHOICE_STEPS = 1;
|
|
@@ -339,6 +340,35 @@ const parseToolInput = (raw) => {
|
|
|
339
340
|
};
|
|
340
341
|
/** A tool's inputSchema with its lazy (function) form, if any, resolved. */
|
|
341
342
|
export const resolveToolInputSchema = (schema) => typeof schema === "function" ? resolveToolInputSchema(schema()) : schema;
|
|
343
|
+
/**
|
|
344
|
+
* The provider-neutral declaration of one tool: the shape every provider's
|
|
345
|
+
* `doGenerate` already converts to its own wire format. The loop uses it for
|
|
346
|
+
* the tools discovery loads mid-turn, and the providers that run the loop use
|
|
347
|
+
* it for their initial declarations, so a tool is declared the same way
|
|
348
|
+
* whether it is there at the start or joins later.
|
|
349
|
+
*/
|
|
350
|
+
export const toNativeToolDeclaration = (name, tool) => ({
|
|
351
|
+
type: "function",
|
|
352
|
+
name,
|
|
353
|
+
description: tool.description ?? "",
|
|
354
|
+
inputSchema: declaredInputSchema(name, tool),
|
|
355
|
+
});
|
|
356
|
+
// A lazy schema that throws must not take the whole request down: SageMaker and
|
|
357
|
+
// Anthropic declared any function-valued schema as the empty object schema
|
|
358
|
+
// before the lazy form was resolved here, so a broken one falls back to that.
|
|
359
|
+
function declaredInputSchema(name, tool) {
|
|
360
|
+
const empty = { type: "object", properties: {} };
|
|
361
|
+
if (!tool.inputSchema) {
|
|
362
|
+
return empty;
|
|
363
|
+
}
|
|
364
|
+
try {
|
|
365
|
+
return convertZodToJsonSchema(resolveToolInputSchema(tool.inputSchema));
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
logger.warn(`[nativeGenerateLoop] input schema of tool "${name}" could not be resolved; declaring it with an empty object schema`, { error: error instanceof Error ? error.message : String(error) });
|
|
369
|
+
return empty;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
342
372
|
/**
|
|
343
373
|
* Validate parsed input against the tool's own schema when it exposes one.
|
|
344
374
|
*
|
|
@@ -486,20 +516,23 @@ async function runGenerateSteps(args, toolExecutionSummaries, stepSpans) {
|
|
|
486
516
|
// answer is that result — not a thrown turn.
|
|
487
517
|
let preReask;
|
|
488
518
|
const hasTools = Boolean(args.tools && args.tools.length > 0);
|
|
489
|
-
// The declarations actually sent.
|
|
490
|
-
// a tool joins toolsRecord mid-turn (discovery loads tools into
|
|
491
|
-
|
|
519
|
+
// The declarations actually sent. It is the caller's own array and grows in
|
|
520
|
+
// place when a tool joins toolsRecord mid-turn (discovery loads tools into
|
|
521
|
+
// it), so anything the caller sized from it, such as the context guard's
|
|
522
|
+
// fixed-overhead estimate, counts the new tools too.
|
|
523
|
+
const liveTools = args.tools;
|
|
524
|
+
const declare = args.declareTool ?? toNativeToolDeclaration;
|
|
492
525
|
const declaredNames = declaredToolRecord(args.tools);
|
|
493
526
|
// Completed-step records for `prepareStep`; one per step that returned.
|
|
494
527
|
const stepRecords = [];
|
|
495
528
|
for (let step = 0; step < args.maxSteps; step++) {
|
|
496
529
|
steps = step + 1;
|
|
497
530
|
stepSpans.begin(steps);
|
|
498
|
-
if (liveTools
|
|
531
|
+
if (liveTools) {
|
|
499
532
|
const loaded = [];
|
|
500
533
|
for (const name of Object.keys(args.toolsRecord)) {
|
|
501
534
|
if (!declaredNames[name]) {
|
|
502
|
-
liveTools.push(
|
|
535
|
+
liveTools.push(declare(name, args.toolsRecord[name]));
|
|
503
536
|
declaredNames[name] = true;
|
|
504
537
|
loaded.push(name);
|
|
505
538
|
}
|
|
@@ -9,7 +9,7 @@ import { convertZodToJsonSchema } from "../utils/schemaConversion.js";
|
|
|
9
9
|
import { withProviderRetry } from "../utils/providerRetry.js";
|
|
10
10
|
import { resolveToolChoice } from "../utils/toolChoice.js";
|
|
11
11
|
import { DEFAULT_MAX_STEPS } from "../core/constants.js";
|
|
12
|
-
import { hasNativeDoGenerate, runNativeGenerateLoop, } from "../core/nativeGenerateLoop.js";
|
|
12
|
+
import { hasNativeDoGenerate, runNativeGenerateLoop, toNativeToolDeclaration, } from "../core/nativeGenerateLoop.js";
|
|
13
13
|
import { generationName } from "../telemetry/observationNames.js";
|
|
14
14
|
import { observeGeneration } from "../telemetry/observation.js";
|
|
15
15
|
import { tracers } from "../telemetry/tracers.js";
|
|
@@ -208,17 +208,7 @@ export class AmazonSageMakerProvider extends BaseProvider {
|
|
|
208
208
|
const toolsRecord = shouldUseTools
|
|
209
209
|
? options.tools || {}
|
|
210
210
|
: {};
|
|
211
|
-
const v3Tools = Object.entries(toolsRecord).map(([name, t]) =>
|
|
212
|
-
const tool = t;
|
|
213
|
-
return {
|
|
214
|
-
type: "function",
|
|
215
|
-
name,
|
|
216
|
-
description: tool.description ?? "",
|
|
217
|
-
inputSchema: (tool.inputSchema
|
|
218
|
-
? convertZodToJsonSchema(tool.inputSchema)
|
|
219
|
-
: { type: "object", properties: {} }),
|
|
220
|
-
};
|
|
221
|
-
});
|
|
211
|
+
const v3Tools = Object.entries(toolsRecord).map(([name, t]) => toNativeToolDeclaration(name, t));
|
|
222
212
|
// Structured output was dropped entirely on this path: the schema never
|
|
223
213
|
// reached the request, and nothing downstream re-imposed it, so a caller
|
|
224
214
|
// asking for an object got whatever JSON coerceJsonToSchema could scrape
|
|
@@ -25,7 +25,7 @@ import { stringifyAnthropicToolOutput } from "./toolOutput.js";
|
|
|
25
25
|
import { createAnthropicLoopAdapter } from "./loopAdapter.js";
|
|
26
26
|
import { DEFAULT_BEFORE_STEP_TIMEOUT_MS } from "../../utils/parameterValidation.js";
|
|
27
27
|
import { runAgenticLoop } from "../../core/loopEngine.js";
|
|
28
|
-
import { hasNativeDoGenerate, resolveStepToolChoice, runNativeGenerateLoop, toPrepareStepRecord, } from "../../core/nativeGenerateLoop.js";
|
|
28
|
+
import { hasNativeDoGenerate, resolveStepToolChoice, runNativeGenerateLoop, toNativeToolDeclaration, toPrepareStepRecord, } from "../../core/nativeGenerateLoop.js";
|
|
29
29
|
import { withProviderRetry } from "../../utils/providerRetry.js";
|
|
30
30
|
import { resolveRequestKind } from "../../core/resolveRequestKind.js";
|
|
31
31
|
import { resolveToolExecutionRecords, toolCallsFromSummaries, } from "../../core/toolExecutionRecorder.js";
|
|
@@ -1528,17 +1528,7 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
1528
1528
|
const toolsRecord = shouldUseTools
|
|
1529
1529
|
? options.tools || {}
|
|
1530
1530
|
: {};
|
|
1531
|
-
const v3Tools = Object.entries(toolsRecord).map(([name, t]) =>
|
|
1532
|
-
const tool = t;
|
|
1533
|
-
return {
|
|
1534
|
-
type: "function",
|
|
1535
|
-
name,
|
|
1536
|
-
description: tool.description ?? "",
|
|
1537
|
-
inputSchema: (tool.inputSchema
|
|
1538
|
-
? convertZodToJsonSchema(tool.inputSchema)
|
|
1539
|
-
: { type: "object", properties: {} }),
|
|
1540
|
-
};
|
|
1541
|
-
});
|
|
1531
|
+
const v3Tools = Object.entries(toolsRecord).map(([name, t]) => toNativeToolDeclaration(name, t));
|
|
1542
1532
|
const hasTools = v3Tools.length > 0;
|
|
1543
1533
|
// Two structured-output routes, and doGenerate implements both. With no
|
|
1544
1534
|
// tools it replaces the tool list with one forced json tool; with tools it
|
|
@@ -36,7 +36,7 @@ import { NoOutputGeneratedError } from "../utils/generationErrors.js";
|
|
|
36
36
|
import { buildNoOutputSentinel, stampNoOutputSpan, } from "../utils/noOutputSentinel.js";
|
|
37
37
|
import { composeAbortSignalsScoped, createTimeoutController, mergeAbortSignals, TimeoutError, } from "../utils/timeout.js";
|
|
38
38
|
import { resolveRequestKind } from "../core/resolveRequestKind.js";
|
|
39
|
-
import { appendJsonSchemaInstruction, hasNativeDoGenerate,
|
|
39
|
+
import { appendJsonSchemaInstruction, hasNativeDoGenerate, resolveStepToolChoice, runNativeGenerateLoop, toNativeToolDeclaration, toPrepareStepRecord, } from "../core/nativeGenerateLoop.js";
|
|
40
40
|
import { resolveToolExecutionRecords, toolCallsFromSummaries, } from "../core/toolExecutionRecorder.js";
|
|
41
41
|
import { convertZodToJsonSchema } from "../utils/schemaConversion.js";
|
|
42
42
|
import { coerceJsonToSchema, recoverScalarRoot, schemaAccepts, } from "../utils/json/coerce.js";
|
|
@@ -925,19 +925,8 @@ export class OpenAIChatCompletionsProvider extends BaseProvider {
|
|
|
925
925
|
? options.tools || (await this.getAllTools())
|
|
926
926
|
: {};
|
|
927
927
|
// v3 tool shape — the same one doGenerate already converts internally.
|
|
928
|
-
// Also handed to the loop, which declares tools discovery loads mid-turn.
|
|
929
|
-
const declareTool = (name, tool) => {
|
|
930
|
-
return {
|
|
931
|
-
type: "function",
|
|
932
|
-
name,
|
|
933
|
-
description: tool.description ?? "",
|
|
934
|
-
inputSchema: tool.inputSchema
|
|
935
|
-
? convertZodToJsonSchema(resolveToolInputSchema(tool.inputSchema))
|
|
936
|
-
: { type: "object", properties: {} },
|
|
937
|
-
};
|
|
938
|
-
};
|
|
939
928
|
const v3Tools = shouldUseTools
|
|
940
|
-
? Object.entries(toolsRecord).map(([name, t]) =>
|
|
929
|
+
? Object.entries(toolsRecord).map(([name, t]) => toNativeToolDeclaration(name, t))
|
|
941
930
|
: undefined;
|
|
942
931
|
const hasTools = !!v3Tools && v3Tools.length > 0;
|
|
943
932
|
// Structured output rides response_format, which is what Output.object did
|
|
@@ -965,14 +954,9 @@ export class OpenAIChatCompletionsProvider extends BaseProvider {
|
|
|
965
954
|
// model has already given. Dropping them is what makes `response_format`
|
|
966
955
|
// legal again on a vendor that refuses the two together.
|
|
967
956
|
withTools = true) => {
|
|
968
|
-
// What this pass sends: the initial declarations
|
|
969
|
-
// for tools discovery loads mid-turn, so the guard counts them too.
|
|
957
|
+
// What this pass sends: the initial declarations, which the loop appends
|
|
958
|
+
// to for tools discovery loads mid-turn, so the guard counts them too.
|
|
970
959
|
const passTools = withTools && v3Tools ? [...v3Tools] : undefined;
|
|
971
|
-
const declarePassTool = (name, tool) => {
|
|
972
|
-
const declaration = declareTool(name, tool);
|
|
973
|
-
passTools?.push(declaration);
|
|
974
|
-
return declaration;
|
|
975
|
-
};
|
|
976
960
|
return runNativeGenerateLoop({
|
|
977
961
|
doGenerate,
|
|
978
962
|
provider: this.providerName,
|
|
@@ -997,9 +981,7 @@ export class OpenAIChatCompletionsProvider extends BaseProvider {
|
|
|
997
981
|
}), this.providerName),
|
|
998
982
|
}),
|
|
999
983
|
conversation: conv,
|
|
1000
|
-
...(passTools
|
|
1001
|
-
? { tools: [...passTools], declareTool: declarePassTool }
|
|
1002
|
-
: {}),
|
|
984
|
+
...(passTools ? { tools: passTools } : {}),
|
|
1003
985
|
toolsRecord,
|
|
1004
986
|
...(withTools && hasTools && options.toolChoice
|
|
1005
987
|
? { toolChoice: resolveToolChoice(options, toolsRecord, true) }
|
|
@@ -137,7 +137,7 @@ export declare function recordsSpanContent(): boolean;
|
|
|
137
137
|
*/
|
|
138
138
|
export declare function isFinishedAttribute(value: string): boolean;
|
|
139
139
|
/**
|
|
140
|
-
* @description Returns a copy of a value with credentials masked: values under keys such as `access_token`, `password`, `authorization` or `set-cookie`,
|
|
140
|
+
* @description Returns a copy of a value with credentials masked: values under keys such as `access_token`, `password`, `authorization` or `set-cookie`, bearer tokens, and `name=value` credentials inside text. Purely numeric values after a credential-looking name (e.g. `max_tokens: 4096`) are left alone.
|
|
141
141
|
* @param value {JsonValue | object} - Content to redact; objects and arrays are walked recursively.
|
|
142
142
|
* @returns {JsonValue | object} A redacted copy, serializing exactly as the input when nothing in it is sensitive.
|
|
143
143
|
* @throws {Error} When the value cannot be walked; tracing callers use `spanContentAttribute`, which turns that into an omitted value.
|
|
@@ -227,29 +227,6 @@ function redactText(text) {
|
|
|
227
227
|
});
|
|
228
228
|
return redacted;
|
|
229
229
|
}
|
|
230
|
-
// A name that says how many, how long or what kind of thing rather than
|
|
231
|
-
// holding the credential (`max_tokens`, `password_policy`, `credential_type`).
|
|
232
|
-
const MEASUREMENT_ENTRY_NAME = /(?:^|_)tokens$|_(?:policy|type|algorithm|count|limit)$/;
|
|
233
|
-
const NUMERIC_TEXT = /^\s*\d+(?:\.\d+)?\s*$/;
|
|
234
|
-
function snakeCased(name) {
|
|
235
|
-
return name
|
|
236
|
-
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
237
|
-
.replace(/[\s.-]+/g, "_")
|
|
238
|
-
.toLowerCase();
|
|
239
|
-
}
|
|
240
|
-
// Headers, environment variables and form fields are often lists of
|
|
241
|
-
// `{ name, value }` or `{ key, value }` entries; when the name is a credential
|
|
242
|
-
// the value is one, exactly as if it were stored under that key. A setting
|
|
243
|
-
// that merely mentions a credential, or a purely numeric value, is not one.
|
|
244
|
-
function credentialEntryName(node) {
|
|
245
|
-
const name = "name" in node ? node.name : "key" in node ? node.key : undefined;
|
|
246
|
-
if (typeof name !== "string" || !("value" in node) || !isSensitiveKey(name)) {
|
|
247
|
-
return undefined;
|
|
248
|
-
}
|
|
249
|
-
const isSetting = MEASUREMENT_ENTRY_NAME.test(snakeCased(name)) ||
|
|
250
|
-
(typeof node.value === "string" && NUMERIC_TEXT.test(node.value));
|
|
251
|
-
return isSetting ? undefined : name;
|
|
252
|
-
}
|
|
253
230
|
function redactNode(value, ancestors) {
|
|
254
231
|
if (typeof value === "string") {
|
|
255
232
|
return redactText(describeDataUrls(value));
|
|
@@ -274,26 +251,17 @@ function redactNode(value, ancestors) {
|
|
|
274
251
|
// No prototype, so a key named __proto__ is data rather than an assignment.
|
|
275
252
|
const redacted = Object.create(null);
|
|
276
253
|
const mimeType = declaredMimeType(value);
|
|
277
|
-
const entryName = credentialEntryName(value);
|
|
278
254
|
for (const [key, entry] of Object.entries(value)) {
|
|
279
|
-
|
|
280
|
-
// parameter used as a map key.
|
|
281
|
-
const safeKey = redactText(key);
|
|
282
|
-
const sensitiveName = key === "value" && entryName !== undefined
|
|
283
|
-
? entryName
|
|
284
|
-
: isSensitiveKey(key)
|
|
285
|
-
? key
|
|
286
|
-
: undefined;
|
|
287
|
-
if (sensitiveName !== undefined &&
|
|
255
|
+
if (isSensitiveKey(key) &&
|
|
288
256
|
(typeof entry === "string" ||
|
|
289
257
|
(typeof entry === "object" && entry !== null))) {
|
|
290
|
-
redacted[
|
|
258
|
+
redacted[key] = redactSensitiveEntry(key, entry);
|
|
291
259
|
continue;
|
|
292
260
|
}
|
|
293
261
|
const placeholder = isBinaryKey(key)
|
|
294
262
|
? binaryPlaceholder(entry, mimeType)
|
|
295
263
|
: undefined;
|
|
296
|
-
redacted[
|
|
264
|
+
redacted[key] = placeholder ?? redactNode(entry, ancestors);
|
|
297
265
|
}
|
|
298
266
|
return redacted;
|
|
299
267
|
}
|
|
@@ -302,7 +270,7 @@ function redactNode(value, ancestors) {
|
|
|
302
270
|
}
|
|
303
271
|
}
|
|
304
272
|
/**
|
|
305
|
-
* @description Returns a copy of a value with credentials masked: values under keys such as `access_token`, `password`, `authorization` or `set-cookie`,
|
|
273
|
+
* @description Returns a copy of a value with credentials masked: values under keys such as `access_token`, `password`, `authorization` or `set-cookie`, bearer tokens, and `name=value` credentials inside text. Purely numeric values after a credential-looking name (e.g. `max_tokens: 4096`) are left alone.
|
|
306
274
|
* @param value {JsonValue | object} - Content to redact; objects and arrays are walked recursively.
|
|
307
275
|
* @returns {JsonValue | object} A redacted copy, serializing exactly as the input when nothing in it is sensitive.
|
|
308
276
|
* @throws {Error} When the value cannot be walked; tracing callers use `spanContentAttribute`, which turns that into an omitted value.
|
package/dist/types/generate.d.ts
CHANGED
|
@@ -1846,11 +1846,12 @@ export type NativeGenerateLoopArgs = {
|
|
|
1846
1846
|
*/
|
|
1847
1847
|
toolsRecord: Record<string, Tool>;
|
|
1848
1848
|
/**
|
|
1849
|
-
* Builds the
|
|
1850
|
-
*
|
|
1851
|
-
*
|
|
1852
|
-
*
|
|
1853
|
-
*
|
|
1849
|
+
* Builds the declaration for a tool that joined `toolsRecord` mid-turn
|
|
1850
|
+
* (discovery's search_tools loads tools into it). Optional: by default the
|
|
1851
|
+
* loop declares such a tool in the provider-neutral shape every provider's
|
|
1852
|
+
* `doGenerate` converts (`toNativeToolDeclaration`), for every provider that
|
|
1853
|
+
* runs this loop. Set it only to declare in another shape. The loop appends
|
|
1854
|
+
* the declarations to `tools` in place.
|
|
1854
1855
|
*/
|
|
1855
1856
|
declareTool?: (name: string, tool: Tool) => Record<string, unknown>;
|
|
1856
1857
|
/** The turn's resolved tool choice, applied per step via `resolveStepToolChoice`. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "13.6.
|
|
3
|
+
"version": "13.6.5",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002/call) for routing, tool selection and context budgeting. MCP-native (4 transports), voice TTS/STT/realtime, RAG, agents, memory, compaction, 9 observability exporters. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · TypeSafe Jev and more.",
|
|
6
6
|
"author": {
|