@juspay/neurolink 10.4.0 → 10.4.2

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.
Files changed (31) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/browser/neurolink.min.js +382 -382
  3. package/dist/core/modules/GenerationHandler.d.ts +24 -0
  4. package/dist/core/modules/GenerationHandler.js +18 -3
  5. package/dist/lib/core/modules/GenerationHandler.d.ts +24 -0
  6. package/dist/lib/core/modules/GenerationHandler.js +18 -3
  7. package/dist/lib/providers/anthropic.js +18 -1
  8. package/dist/lib/providers/googleAiStudio.js +18 -1
  9. package/dist/lib/providers/googleNativeGemini3.d.ts +19 -1
  10. package/dist/lib/providers/googleNativeGemini3.js +61 -4
  11. package/dist/lib/providers/googleVertex.d.ts +48 -0
  12. package/dist/lib/providers/googleVertex.js +204 -108
  13. package/dist/lib/providers/openaiChatCompletionsBase.js +34 -2
  14. package/dist/lib/providers/openaiChatCompletionsClient.d.ts +11 -5
  15. package/dist/lib/providers/openaiChatCompletionsClient.js +14 -8
  16. package/dist/lib/tools/toolDiscovery.d.ts +25 -3
  17. package/dist/lib/tools/toolDiscovery.js +76 -4
  18. package/dist/lib/types/toolResolution.d.ts +10 -0
  19. package/dist/providers/anthropic.js +18 -1
  20. package/dist/providers/googleAiStudio.js +18 -1
  21. package/dist/providers/googleNativeGemini3.d.ts +19 -1
  22. package/dist/providers/googleNativeGemini3.js +61 -4
  23. package/dist/providers/googleVertex.d.ts +48 -0
  24. package/dist/providers/googleVertex.js +204 -108
  25. package/dist/providers/openaiChatCompletionsBase.js +34 -2
  26. package/dist/providers/openaiChatCompletionsClient.d.ts +11 -5
  27. package/dist/providers/openaiChatCompletionsClient.js +14 -8
  28. package/dist/tools/toolDiscovery.d.ts +25 -3
  29. package/dist/tools/toolDiscovery.js +76 -4
  30. package/dist/types/toolResolution.d.ts +10 -0
  31. package/package.json +1 -1
@@ -6,12 +6,19 @@
6
6
  * requested tools, and previously discovered tools) plus ONE `search_tools`
7
7
  * meta-tool whose description embeds a compact name+summary catalog of the
8
8
  * deferred tools. Calling `search_tools` loads matching tools:
9
- * - immediately into the live tool record (providers that re-read the tools
10
- * record between agent-loop steps the AI SDK path — can call them on the
11
- * very next step), and
9
+ * - immediately into the live tool record the AI SDK path re-reads the
10
+ * record between agent-loop steps, and the native loops (Vertex
11
+ * Gemini/Claude, AI Studio, chat-completions, direct Anthropic) re-resolve
12
+ * against it on a dispatch miss and refresh their wire declarations per
13
+ * step — so discovered tools are callable on the very next step, and
12
14
  * - into the session pin set (all providers include them in full on every
13
15
  * subsequent call of the session).
14
16
  *
17
+ * The record additionally carries a symbol-keyed {@link DeferredToolResolver}
18
+ * (see `resolveDeferredTool`) so a loop can hydrate a cataloged tool the
19
+ * model called directly by name WITHOUT a prior search_tools call — the
20
+ * catalog advertises exact names, so models legitimately do this.
21
+ *
15
22
  * Evidence for this design: catalogs past ~30-50 tools measurably degrade
16
23
  * tool-selection accuracy, and deferral+search both cuts definition tokens by
17
24
  * ~85% and RAISES selection accuracy (Anthropic MCP-eval 49%→74% on Opus 4).
@@ -23,6 +30,14 @@ import { z } from "zod";
23
30
  import { tool as createAISDKTool } from "../utils/tool.js";
24
31
  import { convertZodToJsonSchema } from "../utils/schemaConversion.js";
25
32
  import { logger } from "../utils/logger.js";
33
+ /**
34
+ * Symbol key under which the hot record carries its deferred-tool resolver.
35
+ * Symbol-keyed properties are skipped by Object.keys/entries, for-in, and
36
+ * JSON.stringify, so no declaration builder (or the AI SDK) ever sees the
37
+ * resolver as a tool. `Symbol.for` (global registry) keeps the key stable
38
+ * even if this module is loaded twice (ESM/CJS dual load of the bundle).
39
+ */
40
+ const DEFERRED_TOOL_RESOLVER_KEY = Symbol.for("neurolink.deferredToolResolver");
26
41
  /**
27
42
  * Above this many tools, a WARN suggests enabling `tools.discovery` when it
28
43
  * is off. Chosen from the measured degradation range (30-50 tools).
@@ -162,6 +177,35 @@ export function partitionToolsForDiscovery(tools, args) {
162
177
  };
163
178
  });
164
179
  hot["search_tools"] = buildSearchTool(entries, tools, hot, args.onHydrate);
180
+ // Dispatch-miss escape hatch for the native agent loops: hydrate a
181
+ // deferred tool the model called directly by its cataloged name (the
182
+ // catalog advertises exact names, so this is legitimate model behavior,
183
+ // not hallucination). Hydration mutates the hot record and persists the
184
+ // session pin — identical side effects to a search_tools hit.
185
+ const resolver = (name) => {
186
+ if (name in hot) {
187
+ return hot[name];
188
+ }
189
+ if (!deferredSet.has(name)) {
190
+ return undefined;
191
+ }
192
+ const toolDef = tools[name];
193
+ if (!toolDef) {
194
+ return undefined;
195
+ }
196
+ hot[name] = toolDef;
197
+ args.onHydrate([name]);
198
+ logger.debug("[ToolDiscovery] Auto-hydrated deferred tool on direct call", {
199
+ name,
200
+ });
201
+ return toolDef;
202
+ };
203
+ Object.defineProperty(hot, DEFERRED_TOOL_RESOLVER_KEY, {
204
+ value: resolver,
205
+ enumerable: false,
206
+ writable: false,
207
+ configurable: true,
208
+ });
165
209
  logger.debug("[ToolDiscovery] Deferred external tools behind search_tools", {
166
210
  hotCount: Object.keys(hot).length - 1,
167
211
  deferredCount: deferredNames.length,
@@ -169,6 +213,34 @@ export function partitionToolsForDiscovery(tools, args) {
169
213
  });
170
214
  return hot;
171
215
  }
216
+ /**
217
+ * Hydrate-and-return a deferred tool by name, when `record` was produced by
218
+ * `partitionToolsForDiscovery` and `name` is in its deferred catalog.
219
+ * Returns `undefined` for records without a resolver (discovery off) and for
220
+ * names that are genuinely unknown — callers keep their hallucinated-name
221
+ * handling for that case.
222
+ */
223
+ export function resolveDeferredTool(record, name) {
224
+ if (!record) {
225
+ return undefined;
226
+ }
227
+ const resolver = record[DEFERRED_TOOL_RESOLVER_KEY];
228
+ return typeof resolver === "function"
229
+ ? resolver(name)
230
+ : undefined;
231
+ }
232
+ /**
233
+ * Live tool lookup for native agent loops on a dispatch miss: first re-reads
234
+ * the record (a tool hydrated by search_tools after the loop built its
235
+ * pre-step snapshot), then falls back to auto-hydrating from the deferred
236
+ * catalog. Returns `undefined` only when the name is genuinely unknown.
237
+ */
238
+ export function resolveLiveTool(record, name) {
239
+ if (!record) {
240
+ return undefined;
241
+ }
242
+ return record[name] ?? resolveDeferredTool(record, name);
243
+ }
172
244
  function buildSearchTool(entries, allTools, hotRecord, onHydrate) {
173
245
  const catalog = renderCatalog(entries);
174
246
  const searchTool = createAISDKTool({
@@ -221,7 +293,7 @@ function buildSearchTool(entries, allTools, hotRecord, onHydrate) {
221
293
  return {
222
294
  found: loaded.length,
223
295
  tools: loaded,
224
- message: "These tools are now loaded for this session. Call them directly by name with arguments matching their inputSchema. If a call reports the tool as unavailable, it will be available from the next message onward.",
296
+ message: "These tools are now loaded for this session. Call them directly by name with arguments matching their inputSchema.",
225
297
  };
226
298
  },
227
299
  });
@@ -8,6 +8,7 @@
8
8
  * `BaseProvider` that every generate/stream path passes through.
9
9
  */
10
10
  import type { ToolConfig } from "./config.js";
11
+ import type { Tool } from "./tools.js";
11
12
  /**
12
13
  * The resolved, merged tool policy for one request. Produced by
13
14
  * `resolveToolPolicy()` (src/lib/tools/toolPolicy.ts) and consumed by
@@ -71,3 +72,12 @@ export type DeferredToolIndexEntry = {
71
72
  /** Originating MCP server id, when known. */
72
73
  serverId?: string;
73
74
  };
75
+ /**
76
+ * Resolver attached (under a symbol key, invisible to enumeration) to the
77
+ * hot tool record by `partitionToolsForDiscovery`. Given a deferred tool's
78
+ * name it hydrates that tool into the record, persists the session pin, and
79
+ * returns it — `undefined` when the name is not in the deferred catalog.
80
+ * Native agent loops call it on a dispatch miss so a model that calls a
81
+ * cataloged tool directly (without `search_tools` first) still succeeds.
82
+ */
83
+ export type DeferredToolResolver = (name: string) => Tool | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "10.4.0",
3
+ "version": "10.4.2",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (connect any MCP server), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
6
6
  "author": {