@juspay/neurolink 10.4.1 → 10.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/browser/neurolink.min.js +386 -389
  3. package/dist/cli/commands/proxy.d.ts +1 -1
  4. package/dist/cli/commands/proxy.js +124 -56
  5. package/dist/cli/commands/proxyAnalyze.js +10 -1
  6. package/dist/lib/providers/anthropic.js +18 -1
  7. package/dist/lib/providers/googleAiStudio.js +18 -1
  8. package/dist/lib/providers/googleNativeGemini3.d.ts +19 -1
  9. package/dist/lib/providers/googleNativeGemini3.js +61 -4
  10. package/dist/lib/providers/googleVertex.d.ts +48 -0
  11. package/dist/lib/providers/googleVertex.js +204 -108
  12. package/dist/lib/providers/openaiChatCompletionsBase.js +34 -2
  13. package/dist/lib/providers/openaiChatCompletionsClient.d.ts +11 -5
  14. package/dist/lib/providers/openaiChatCompletionsClient.js +14 -8
  15. package/dist/lib/proxy/proxyAnalysis.js +136 -12
  16. package/dist/lib/proxy/requestLogger.d.ts +2 -0
  17. package/dist/lib/proxy/requestLogger.js +72 -13
  18. package/dist/lib/proxy/rollingProxyServer.js +79 -8
  19. package/dist/lib/proxy/rollingWorkerProcess.js +20 -15
  20. package/dist/lib/proxy/rollingWorkerProtocol.js +3 -0
  21. package/dist/lib/proxy/rollingWorkerSupervisor.d.ts +1 -0
  22. package/dist/lib/proxy/rollingWorkerSupervisor.js +31 -11
  23. package/dist/lib/proxy/runtimeConfig.d.ts +1 -0
  24. package/dist/lib/proxy/runtimeConfig.js +20 -5
  25. package/dist/lib/proxy/socketWorkerRuntime.js +41 -13
  26. package/dist/lib/server/routes/claudeProxyRoutes.js +63 -75
  27. package/dist/lib/tools/toolDiscovery.d.ts +25 -3
  28. package/dist/lib/tools/toolDiscovery.js +76 -4
  29. package/dist/lib/types/proxy.d.ts +31 -1
  30. package/dist/lib/types/toolResolution.d.ts +10 -0
  31. package/dist/providers/anthropic.js +18 -1
  32. package/dist/providers/googleAiStudio.js +18 -1
  33. package/dist/providers/googleNativeGemini3.d.ts +19 -1
  34. package/dist/providers/googleNativeGemini3.js +61 -4
  35. package/dist/providers/googleVertex.d.ts +48 -0
  36. package/dist/providers/googleVertex.js +204 -108
  37. package/dist/providers/openaiChatCompletionsBase.js +34 -2
  38. package/dist/providers/openaiChatCompletionsClient.d.ts +11 -5
  39. package/dist/providers/openaiChatCompletionsClient.js +14 -8
  40. package/dist/proxy/proxyAnalysis.js +136 -12
  41. package/dist/proxy/requestLogger.d.ts +2 -0
  42. package/dist/proxy/requestLogger.js +72 -13
  43. package/dist/proxy/rollingProxyServer.js +79 -8
  44. package/dist/proxy/rollingWorkerProcess.js +20 -15
  45. package/dist/proxy/rollingWorkerProtocol.js +3 -0
  46. package/dist/proxy/rollingWorkerSupervisor.d.ts +1 -0
  47. package/dist/proxy/rollingWorkerSupervisor.js +31 -11
  48. package/dist/proxy/runtimeConfig.d.ts +1 -0
  49. package/dist/proxy/runtimeConfig.js +20 -5
  50. package/dist/proxy/socketWorkerRuntime.js +41 -13
  51. package/dist/server/routes/claudeProxyRoutes.js +63 -75
  52. package/dist/tools/toolDiscovery.d.ts +25 -3
  53. package/dist/tools/toolDiscovery.js +76 -4
  54. package/dist/types/proxy.d.ts +31 -1
  55. package/dist/types/toolResolution.d.ts +10 -0
  56. package/package.json +1 -1
@@ -1121,6 +1121,7 @@ export type ProxyAnalysisAccount = {
1121
1121
  unclassifiedRateLimits: number;
1122
1122
  };
1123
1123
  /** Offline report generated from proxy request, attempt, and lifecycle logs. */
1124
+ export type ProxyAnalysisStreamName = "lifecycle" | "requests" | "attempts" | "debug";
1124
1125
  export type ProxyAnalysisReport = {
1125
1126
  generatedAt: string;
1126
1127
  since: string;
@@ -1129,6 +1130,7 @@ export type ProxyAnalysisReport = {
1129
1130
  lifecycle: number;
1130
1131
  requests: number;
1131
1132
  attempts: number;
1133
+ debug: number;
1132
1134
  };
1133
1135
  coverage: {
1134
1136
  lifecycle: boolean;
@@ -1143,6 +1145,20 @@ export type ProxyAnalysisReport = {
1143
1145
  unsupportedLifecycleLines: number;
1144
1146
  lifecycleSequenceGaps: number;
1145
1147
  lifecycleSequenceDuplicates: number;
1148
+ streams: Record<ProxyAnalysisStreamName, {
1149
+ observedFrom: string | null;
1150
+ observedTo: string | null;
1151
+ startsAtOrBeforeRequestedWindow: boolean;
1152
+ }>;
1153
+ bodyArtifacts: {
1154
+ capturesIndexed: number;
1155
+ artifactsReferenced: number;
1156
+ artifactsPresent: number;
1157
+ artifactsMissing: number;
1158
+ invalidPaths: number;
1159
+ writeFailures: number;
1160
+ truncatedCaptures: number;
1161
+ };
1146
1162
  };
1147
1163
  lifecycle: {
1148
1164
  accepted: number;
@@ -1392,6 +1408,7 @@ export type StoredBodyArtifact = {
1392
1408
  storedFileBytes?: number;
1393
1409
  redactedBody?: string;
1394
1410
  bodyTruncated?: boolean;
1411
+ bodyWriteFailed?: boolean;
1395
1412
  };
1396
1413
  /** File the proxy logger tracks for rotation and cleanup. */
1397
1414
  export type ManagedLogFile = {
@@ -1653,6 +1670,11 @@ export type ProxyWorkerStatusMessage = {
1653
1670
  generation: number;
1654
1671
  pid: number;
1655
1672
  socketId: string;
1673
+ } | {
1674
+ type: "proxy-worker:replacement-requested";
1675
+ generation: number;
1676
+ pid: number;
1677
+ reason: "environment";
1656
1678
  };
1657
1679
  export type ProxyWorkerSocketMessage = {
1658
1680
  type: "proxy-worker:socket";
@@ -1661,6 +1683,8 @@ export type ProxyWorkerSocketMessage = {
1661
1683
  };
1662
1684
  export type ProxyWorkerIpcMessage = ProxyWorkerControlMessage | ProxyWorkerStatusMessage | ProxyWorkerSocketMessage;
1663
1685
  export type TransferableProxySocket = Pick<import("node:net").Socket, "destroy" | "end" | "pause" | "resume" | "once">;
1686
+ /** A transferred socket whose temporary handoff listeners can be detached. */
1687
+ export type DetachableTransferableProxySocket = TransferableProxySocket & Pick<import("node:net").Socket, "off">;
1664
1688
  export type RollingWorkerHandle = {
1665
1689
  pid: number;
1666
1690
  sendControl: (message: ProxyWorkerControlMessage) => void;
@@ -1714,6 +1738,11 @@ export type RollingWorkerSupervisorOptions = {
1714
1738
  socketQueueTimeoutMs?: number;
1715
1739
  shutdownTimeoutMs?: number;
1716
1740
  onStateChange?: (snapshot: RollingWorkerSupervisorSnapshot) => void;
1741
+ onReplacementRequested?: (request: {
1742
+ generation: number;
1743
+ pid: number;
1744
+ reason: "environment";
1745
+ }) => void;
1717
1746
  log?: (message: string) => void;
1718
1747
  };
1719
1748
  export type RollingProxyServerOptions = {
@@ -1854,6 +1883,7 @@ export type ProxyRuntimeConfigReloadResult = {
1854
1883
  applied: boolean;
1855
1884
  changed: boolean;
1856
1885
  generation: number;
1886
+ environmentChanged?: boolean;
1857
1887
  error?: string;
1858
1888
  };
1859
1889
  /** Safe runtime configuration diagnostics exposed through proxy status. */
@@ -1933,7 +1963,7 @@ export type StatusStats = {
1933
1963
  transientRateLimits?: number;
1934
1964
  quotaRateLimits?: number;
1935
1965
  cooling: boolean;
1936
- status?: "active" | "cooling" | "disabled" | "excluded" | "removed";
1966
+ status?: "active" | "cooling" | "disabled" | "excluded" | "removed" | "unattributed";
1937
1967
  }[];
1938
1968
  persistence?: ProxyStatsPersistenceStatus;
1939
1969
  };
@@ -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;
@@ -15,6 +15,7 @@ import { logger } from "../utils/logger.js";
15
15
  import { redactUrlCredentials } from "../utils/logSanitize.js";
16
16
  import { ANTHROPIC_MAX_CACHE_BREAKPOINTS, applyAnthropicHistoryCacheBreakpoints, countAnthropicCacheMarkers, } from "../utils/anthropicCacheBreakpoints.js";
17
17
  import { calculateCost } from "../utils/pricing.js";
18
+ import { resolveDeferredTool } from "../tools/toolDiscovery.js";
18
19
  import { createAnthropicConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
19
20
  import { composeAbortSignals, createTimeoutController, mergeAbortSignals, TimeoutError, } from "../utils/timeout.js";
20
21
  import { resolveToolChoice } from "../utils/toolChoice.js";
@@ -1400,6 +1401,18 @@ export class AnthropicProvider extends BaseProvider {
1400
1401
  let totalCacheWrite = 0;
1401
1402
  let lastStop = null;
1402
1403
  for (let step = 0; step < maxSteps; step++) {
1404
+ // Mid-turn discovery sync: search_tools (tools.discovery) hydrates
1405
+ // new tools into toolsRecord between steps; Claude only calls tools
1406
+ // declared in the request, so advertise them now (`params` below
1407
+ // rebuilds from anthropicTools every step).
1408
+ if (anthropicTools) {
1409
+ const declared = new Set(anthropicTools.map((t) => t.name));
1410
+ const hydrated = Object.fromEntries(Object.entries(toolsRecord).filter(([name]) => !declared.has(name)));
1411
+ if (Object.keys(hydrated).length > 0) {
1412
+ anthropicTools.push(...(toolsToAnthropic(hydrated) ?? []));
1413
+ logger.info(`[Anthropic] ${Object.keys(hydrated).length} tool(s) hydrated mid-turn via discovery: ${Object.keys(hydrated).join(", ")}`);
1414
+ }
1415
+ }
1403
1416
  // Prompt-cache parity with the native Vertex+Claude path — rolling
1404
1417
  // history breakpoints, re-applied per step so the stable prefix
1405
1418
  // stays byte-identical while the breakpoint follows the growing
@@ -1566,7 +1579,11 @@ export class AnthropicProvider extends BaseProvider {
1566
1579
  args,
1567
1580
  });
1568
1581
  toolsUsed.push(acc.name);
1569
- const tool = toolsRecord[acc.name];
1582
+ // Live record lookup, then deferred-catalog auto-hydration: with
1583
+ // tools.discovery on, the model may call a cataloged tool it never
1584
+ // loaded via search_tools — a real tool, not a hallucination.
1585
+ const tool = (toolsRecord[acc.name] ??
1586
+ resolveDeferredTool(toolsRecord, acc.name));
1570
1587
  try {
1571
1588
  if (!tool?.execute) {
1572
1589
  throw new Error(`Tool not found: ${acc.name}`);
@@ -10,7 +10,7 @@ import { composeAbortSignals, createTimeoutController, TimeoutError, } from "../
10
10
  import { withTimeout } from "../utils/async/index.js";
11
11
  import { estimateTokens } from "../utils/tokenEstimation.js";
12
12
  import { transformToolExecutions } from "../utils/transformationUtils.js";
13
- import { buildGeminiResponseSchema, buildNativeConfig, buildNativeToolDeclarations, collectStreamChunks, collectStreamChunksIncremental, computeMaxSteps, createTextChannel, buildUserPartsWithMultimodal, executeNativeToolCalls, extractTextFromParts, extractThoughtSignature, handleMaxStepsTermination, prependConversationMessages, pushModelResponseToHistory, DedupExecuteMap, } from "./googleNativeGemini3.js";
13
+ import { buildGeminiResponseSchema, buildNativeConfig, buildNativeToolDeclarations, collectStreamChunks, collectStreamChunksIncremental, computeMaxSteps, createTextChannel, buildUserPartsWithMultimodal, executeNativeToolCalls, extractTextFromParts, extractThoughtSignature, handleMaxStepsTermination, prependConversationMessages, pushModelResponseToHistory, refreshNativeToolDeclarations, DedupExecuteMap, } from "./googleNativeGemini3.js";
14
14
  import { createProxyFetch } from "../proxy/proxyFetch.js";
15
15
  // Google AI Live API types now imported from ../types/providerSpecific.js
16
16
  // Import proper types for multimodal message handling
@@ -523,10 +523,12 @@ export class GoogleAIStudioProvider extends BaseProvider {
523
523
  let toolsConfig;
524
524
  let executeMap = new DedupExecuteMap();
525
525
  let originalNameMap = new Map();
526
+ let declarationsResult;
526
527
  if (options.tools &&
527
528
  Object.keys(options.tools).length > 0 &&
528
529
  !options.disableTools) {
529
530
  const result = buildNativeToolDeclarations(options.tools);
531
+ declarationsResult = result;
530
532
  toolsConfig = result.toolsConfig;
531
533
  executeMap = result.executeMap;
532
534
  originalNameMap = result.originalNameMap;
@@ -597,6 +599,11 @@ export class GoogleAIStudioProvider extends BaseProvider {
597
599
  : new Error("Request aborted");
598
600
  }
599
601
  step++;
602
+ // Mid-turn discovery sync: advertise tools hydrated into the
603
+ // live record by search_tools during the previous step.
604
+ if (declarationsResult) {
605
+ refreshNativeToolDeclarations(options.tools, declarationsResult);
606
+ }
600
607
  logger.debug(`[GoogleAIStudio] Native SDK step ${step}/${maxSteps}`);
601
608
  try {
602
609
  const rawStream = await client.models.generateContentStream({
@@ -640,6 +647,8 @@ export class GoogleAIStudioProvider extends BaseProvider {
640
647
  abortSignal: composedSignal,
641
648
  originalNameMap,
642
649
  toolExecutions,
650
+ liveTools: options.tools,
651
+ declarations: declarationsResult,
643
652
  });
644
653
  // Persist this step's tool calls/results into conversation
645
654
  // memory. Without this, tool_call / tool_result rows never
@@ -810,11 +819,13 @@ export class GoogleAIStudioProvider extends BaseProvider {
810
819
  let toolsConfig;
811
820
  let executeMap = new DedupExecuteMap();
812
821
  let originalNameMap = new Map();
822
+ let declarationsResult;
813
823
  const shouldUseTools = !options.disableTools;
814
824
  if (shouldUseTools) {
815
825
  const tools = options.tools || {};
816
826
  if (Object.keys(tools).length > 0) {
817
827
  const result = buildNativeToolDeclarations(tools);
828
+ declarationsResult = result;
818
829
  toolsConfig = result.toolsConfig;
819
830
  executeMap = result.executeMap;
820
831
  originalNameMap = result.originalNameMap;
@@ -856,6 +867,10 @@ export class GoogleAIStudioProvider extends BaseProvider {
856
867
  : new Error("Request aborted");
857
868
  }
858
869
  step++;
870
+ // Mid-turn discovery sync — see the stream twin.
871
+ if (declarationsResult) {
872
+ refreshNativeToolDeclarations(options.tools, declarationsResult);
873
+ }
859
874
  logger.debug(`[GoogleAIStudio] Native SDK generate step ${step}/${maxSteps}`);
860
875
  try {
861
876
  const stream = await client.models.generateContentStream({
@@ -894,6 +909,8 @@ export class GoogleAIStudioProvider extends BaseProvider {
894
909
  toolExecutions,
895
910
  abortSignal: composedSignal,
896
911
  originalNameMap,
912
+ liveTools: options.tools,
913
+ declarations: declarationsResult,
897
914
  });
898
915
  // Persist this step's tool calls/results into conversation memory.
899
916
  const stepToolCalls = allToolCalls.slice(toolCallsBefore);
@@ -82,7 +82,16 @@ export declare function normalizeToolsForJsonSchemaProvider(tools: Record<string
82
82
  *
83
83
  * This handles both Zod schemas and plain JSON Schema objects for tool parameters.
84
84
  */
85
- export declare function buildNativeToolDeclarations(tools: Record<string, Tool>): NativeToolDeclarationsResult;
85
+ export declare function buildNativeToolDeclarations(tools: Record<string, Tool>, reservedNames?: ReadonlySet<string>): NativeToolDeclarationsResult;
86
+ /**
87
+ * Mid-turn tool sync for the native Gemini loops that build their snapshot
88
+ * via buildNativeToolDeclarations. `search_tools` (tools.discovery) hydrates
89
+ * discovered tools into the live record between steps; without this refresh
90
+ * they stay invisible to the rest of the turn and every call dies as
91
+ * TOOL_NOT_FOUND. Mutates the snapshot in place — the request config holds
92
+ * `toolsConfig` by reference — and returns true when anything was added.
93
+ */
94
+ export declare function refreshNativeToolDeclarations(liveTools: Record<string, Tool> | undefined, current: NativeToolDeclarationsResult): boolean;
86
95
  /**
87
96
  * Build the native @google/genai config object shared by stream and generate.
88
97
  *
@@ -217,6 +226,15 @@ export declare function executeNativeToolCalls(logLabel: string, stepFunctionCal
217
226
  }>;
218
227
  abortSignal?: AbortSignal;
219
228
  originalNameMap?: Map<string, string>;
229
+ /**
230
+ * Live tool record + declaration snapshot for mid-turn discovery: on a
231
+ * dispatch miss the executor re-resolves against `liveTools` (hydrated
232
+ * by search_tools, or auto-hydrated from the deferred catalog) and syncs
233
+ * `declarations` in place. `declarations.executeMap` must be the same
234
+ * map passed as the `executeMap` argument (true at every call site).
235
+ */
236
+ liveTools?: Record<string, Tool>;
237
+ declarations?: NativeToolDeclarationsResult;
220
238
  }): Promise<NativeFunctionResponse[]>;
221
239
  /**
222
240
  * Handle maxSteps termination by producing a final answer when the model was
@@ -15,6 +15,7 @@ import { DEFAULT_CONTEXT_GUARD_RATIO, DEFAULT_MAX_STEPS, DEFAULT_TOOL_MAX_RETRIE
15
15
  import { logger } from "../utils/logger.js";
16
16
  import { convertZodToJsonSchema, ensureNestedSchemaTypes, inlineJsonSchema, isZodSchema, normalizeJsonSchemaObject, } from "../utils/schemaConversion.js";
17
17
  import { createNativeThinkingConfig } from "../utils/thinkingConfig.js";
18
+ import { resolveLiveTool } from "../tools/toolDiscovery.js";
18
19
  import { jsonSchema as aiJsonSchema, tool as createAISDKTool, } from "../utils/tool.js";
19
20
  // ── Functions ──
20
21
  /** Stable, key-order-independent serialization of tool args for the dedup key. */
@@ -367,7 +368,7 @@ export function normalizeToolsForJsonSchemaProvider(tools) {
367
368
  *
368
369
  * This handles both Zod schemas and plain JSON Schema objects for tool parameters.
369
370
  */
370
- export function buildNativeToolDeclarations(tools) {
371
+ export function buildNativeToolDeclarations(tools, reservedNames) {
371
372
  const functionDeclarations = [];
372
373
  const executeMap = new DedupExecuteMap();
373
374
  const skippedTools = [];
@@ -380,8 +381,10 @@ export function buildNativeToolDeclarations(tools) {
380
381
  // execute are still pushed to functionDeclarations). The originalNameMap
381
382
  // lets the calling stream loop translate Google-returned function-call
382
383
  // names back to the consumer-facing identifier so the sanitization is
383
- // transport-only.
384
- const usedNames = new Set();
384
+ // transport-only. `reservedNames` seeds the collision set so a mid-turn
385
+ // refresh (see refreshNativeToolDeclarations) never re-issues a safe name
386
+ // already assigned by the pre-loop snapshot.
387
+ const usedNames = new Set(reservedNames ?? []);
385
388
  const originalNameMap = new Map();
386
389
  for (const [name, tool] of Object.entries(tools)) {
387
390
  try {
@@ -442,6 +445,36 @@ export function buildNativeToolDeclarations(tools) {
442
445
  originalNameMap,
443
446
  };
444
447
  }
448
+ /**
449
+ * Mid-turn tool sync for the native Gemini loops that build their snapshot
450
+ * via buildNativeToolDeclarations. `search_tools` (tools.discovery) hydrates
451
+ * discovered tools into the live record between steps; without this refresh
452
+ * they stay invisible to the rest of the turn and every call dies as
453
+ * TOOL_NOT_FOUND. Mutates the snapshot in place — the request config holds
454
+ * `toolsConfig` by reference — and returns true when anything was added.
455
+ */
456
+ export function refreshNativeToolDeclarations(liveTools, current) {
457
+ if (!liveTools) {
458
+ return false;
459
+ }
460
+ const declaredOriginals = new Set(current.originalNameMap.values());
461
+ const missing = Object.entries(liveTools).filter(([name]) => !declaredOriginals.has(name));
462
+ if (missing.length === 0) {
463
+ return false;
464
+ }
465
+ const built = buildNativeToolDeclarations(Object.fromEntries(missing), new Set(current.originalNameMap.keys()));
466
+ current.toolsConfig[0].functionDeclarations.push(...built.toolsConfig[0].functionDeclarations);
467
+ for (const [safeName, originalName] of built.originalNameMap) {
468
+ current.originalNameMap.set(safeName, originalName);
469
+ }
470
+ for (const [safeName, execute] of built.executeMap) {
471
+ current.executeMap.set(safeName, execute);
472
+ }
473
+ logger.info(`[buildNativeToolDeclarations] ${missing.length} tool(s) hydrated mid-turn via discovery: ${missing
474
+ .map(([name]) => name)
475
+ .join(", ")}`);
476
+ return true;
477
+ }
445
478
  /**
446
479
  * Build the native @google/genai config object shared by stream and generate.
447
480
  *
@@ -795,7 +828,31 @@ export async function executeNativeToolCalls(logLabel, stepFunctionCalls, execut
795
828
  });
796
829
  continue;
797
830
  }
798
- const execute = executeMap.get(call.name);
831
+ let execute = executeMap.get(call.name);
832
+ if (!execute && options?.declarations) {
833
+ // Snapshot miss: the tool may have been hydrated into the live record
834
+ // by search_tools within this very step batch, or the model called a
835
+ // deferred catalog tool directly by its advertised name.
836
+ const liveTool = resolveLiveTool(options.liveTools, exposedName);
837
+ if (liveTool?.execute) {
838
+ refreshNativeToolDeclarations(options.liveTools, options.declarations);
839
+ // NOT_FOUND strikes accrued while the tool was deferred are snapshot
840
+ // artifacts, not real failures — reset so the breaker starts clean.
841
+ failedTools.delete(call.name);
842
+ // The refresh registered the executor under its Google-safe name —
843
+ // resolve it for this dispatch (later calls use the declared name).
844
+ for (const [safeName, originalName] of options.declarations
845
+ .originalNameMap) {
846
+ if (originalName === exposedName) {
847
+ execute = executeMap.get(safeName);
848
+ break;
849
+ }
850
+ }
851
+ if (execute) {
852
+ logger.info(`${logLabel} Tool "${exposedName}" resolved mid-turn via discovery — executing.`);
853
+ }
854
+ }
855
+ }
799
856
  if (execute) {
800
857
  try {
801
858
  // AI SDK Tool execute requires (args, options) - provide minimal options
@@ -152,6 +152,54 @@ export declare class GoogleVertexProvider extends BaseProvider {
152
152
  * Create @google/genai client configured for Vertex AI
153
153
  */
154
154
  private createVertexGenAIClient;
155
+ /**
156
+ * Convert one AI-SDK tool into a Vertex Gemini function declaration.
157
+ * Single source for the pre-loop snapshot AND the mid-turn discovery
158
+ * refresh, so tools hydrated by search_tools get the exact same schema
159
+ * treatment (inline, typed, additionalProperties stripped).
160
+ */
161
+ private buildGeminiFunctionDeclaration;
162
+ /**
163
+ * Mid-turn tool sync for the native Gemini loops. `search_tools` hydrates
164
+ * discovered tools into the live `options.tools` record between steps, but
165
+ * the loop's declarations + executeMap are a pre-loop snapshot — without
166
+ * this refresh, a tool discovered this turn stays invisible to the rest of
167
+ * the turn and every call to it dies as TOOL_NOT_FOUND. Mutates the
168
+ * declaration array in place (the request config holds it by reference)
169
+ * and clears breaker strikes accrued while the tool was still deferred.
170
+ */
171
+ private refreshGeminiToolDeclarations;
172
+ /**
173
+ * Dispatch-miss recovery for the native Gemini loops: the model called a
174
+ * name missing from the executeMap snapshot. Re-read the live record (a
175
+ * tool hydrated by search_tools in this very step batch) or auto-hydrate a
176
+ * deferred catalog tool the model called directly by its advertised name.
177
+ * Returns the dedup-wrapped executor, or undefined when the name is
178
+ * genuinely unknown — callers keep TOOL_NOT_FOUND for that case.
179
+ */
180
+ private resolveGeminiToolOnMiss;
181
+ /**
182
+ * Convert one AI-SDK tool into an Anthropic (Claude-on-Vertex) tool
183
+ * declaration. Single source for the pre-loop snapshot AND the mid-turn
184
+ * discovery refresh — Anthropic validates input_schema as JSON Schema
185
+ * draft 2020-12 and rejects OpenAPI-3 dialect (`nullable: true`), so this
186
+ * uses the default JSON Schema target, matching the direct anthropic
187
+ * provider. The Gemini paths keep "openApi3".
188
+ */
189
+ private buildAnthropicToolDeclaration;
190
+ /**
191
+ * Mid-turn tool sync for the Claude-on-Vertex loops — the Anthropic
192
+ * counterpart of refreshGeminiToolDeclarations. Claude only calls tools
193
+ * present in the request's `tools` array, so without this per-step refresh
194
+ * a tool discovered via search_tools is unreachable for the rest of the
195
+ * turn. Mutates the array in place (requestParams holds it by reference).
196
+ */
197
+ private refreshAnthropicToolDeclarations;
198
+ /**
199
+ * Dispatch-miss recovery for the Claude-on-Vertex loops — the Anthropic
200
+ * counterpart of resolveGeminiToolOnMiss.
201
+ */
202
+ private resolveAnthropicToolOnMiss;
155
203
  /**
156
204
  * Execute stream using native @google/genai SDK for Gemini 3 models on Vertex AI
157
205
  * This bypasses @ai-sdk/google-vertex to properly handle thought_signature