@juspay/neurolink 12.12.11 → 12.12.13

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 (42) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/dist/browser/neurolink.min.js +216 -216
  3. package/dist/constants/contextWindows.js +1 -0
  4. package/dist/constants/enums.d.ts +1 -0
  5. package/dist/constants/enums.js +7 -0
  6. package/dist/core/baseProvider.js +4 -4
  7. package/dist/core/modules/structuredOutputPolicy.d.ts +6 -6
  8. package/dist/core/modules/structuredOutputPolicy.js +6 -6
  9. package/dist/core/nativeGenerateLoop.js +11 -0
  10. package/dist/core/nativeToolFormat.js +2 -2
  11. package/dist/factories/providerDescriptors.js +1 -1
  12. package/dist/factories/providerRegistry.js +4 -1
  13. package/dist/neurolink.js +1 -1
  14. package/dist/providers/amazonSagemaker.js +1 -0
  15. package/dist/providers/anthropic/cacheControl.d.ts +3 -3
  16. package/dist/providers/anthropic/cacheControl.js +3 -3
  17. package/dist/providers/anthropic/client.js +26 -8
  18. package/dist/providers/configuredOpenAICompat.d.ts +1 -1
  19. package/dist/providers/configuredOpenAICompat.js +1 -1
  20. package/dist/providers/googleAiStudio/client.js +2 -3
  21. package/dist/providers/googleVertex/client.js +2 -2
  22. package/dist/providers/nvidiaNim/client.js +11 -1
  23. package/dist/providers/openaiChatCompletionsBase.d.ts +4 -4
  24. package/dist/providers/openaiChatCompletionsBase.js +11 -10
  25. package/dist/types/context.d.ts +0 -22
  26. package/dist/types/generate.d.ts +2 -17
  27. package/dist/types/providers.d.ts +1 -27
  28. package/dist/utils/anthropicCacheBreakpoints.d.ts +6 -6
  29. package/dist/utils/anthropicCacheBreakpoints.js +6 -6
  30. package/dist/utils/json/coerce.d.ts +3 -2
  31. package/dist/utils/json/coerce.js +3 -2
  32. package/dist/utils/modelChoices.js +1 -1
  33. package/dist/utils/pricing.js +8 -0
  34. package/dist/utils/tokenUtils.d.ts +0 -1
  35. package/dist/utils/tokenUtils.js +0 -1
  36. package/dist/utils/tool.js +0 -3
  37. package/docs-site/static/search-index.json +1 -1
  38. package/package.json +3 -1
  39. package/dist/context/stepBudgetGuard.d.ts +0 -61
  40. package/dist/context/stepBudgetGuard.js +0 -357
  41. package/dist/core/serviceRegistry.d.ts +0 -40
  42. package/dist/core/serviceRegistry.js +0 -112
@@ -67,6 +67,7 @@ export const MODEL_CONTEXT_WINDOWS = {
67
67
  "mistralai/mixtral-8x7b-instruct-v0.1": 32_768,
68
68
  "microsoft/phi-4": 16_384,
69
69
  "google/gemma-3-27b-it": 8_192,
70
+ "openai/gpt-oss-20b": 131_072,
70
71
  },
71
72
  "lm-studio": {
72
73
  _default: 8_192,
@@ -644,6 +644,7 @@ export declare enum DeepSeekModels {
644
644
  * Note: NIM hosts hundreds of models; pass arbitrary IDs via --model.
645
645
  */
646
646
  export declare enum NvidiaNimModels {
647
+ GPT_OSS_20B = "openai/gpt-oss-20b",
647
648
  LLAMA_3_3_70B_INSTRUCT = "meta/llama-3.3-70b-instruct",
648
649
  LLAMA_3_1_405B_INSTRUCT = "meta/llama-3.1-405b-instruct",
649
650
  LLAMA_3_1_70B_INSTRUCT = "meta/llama-3.1-70b-instruct",
@@ -872,6 +872,13 @@ export var DeepSeekModels;
872
872
  */
873
873
  export var NvidiaNimModels;
874
874
  (function (NvidiaNimModels) {
875
+ // NVIDIA retired a large part of this list upstream on 2026-08-26 —
876
+ // llama-3.3-70b, llama-3.1-70b, llama-3.2-90b-vision, the deepseek-r1
877
+ // distill and gemma-3-27b all answer "no longer available" now. The members
878
+ // are kept so existing callers still compile, but the provider default
879
+ // below must point at something live: gpt-oss-20b is on the current roster
880
+ // and was probed for text, streaming, tool calling and structured output.
881
+ NvidiaNimModels["GPT_OSS_20B"] = "openai/gpt-oss-20b";
875
882
  // Meta Llama
876
883
  NvidiaNimModels["LLAMA_3_3_70B_INSTRUCT"] = "meta/llama-3.3-70b-instruct";
877
884
  NvidiaNimModels["LLAMA_3_1_405B_INSTRUCT"] = "meta/llama-3.1-405b-instruct";
@@ -1260,7 +1260,7 @@ export class BaseProvider {
1260
1260
  [ATTR.NL_PROVIDER]: this.providerName || "unknown",
1261
1261
  },
1262
1262
  });
1263
- // Set this span as the active context so child spans (GenerationHandler, etc.) become descendants
1263
+ // Set this span as the active context so child spans (provider calls, tool executions) become descendants
1264
1264
  const activeCtx = trace.setSpan(context.active(), otelSpan);
1265
1265
  const otelSpanState = { ended: false };
1266
1266
  return await context.with(activeCtx, async () => this.runGenerateInActiveContext(options, startTime, otelSpan, otelSpanState));
@@ -1706,9 +1706,9 @@ export class BaseProvider {
1706
1706
  analytics: result.analytics,
1707
1707
  evaluation: result.evaluation,
1708
1708
  audio: result.audio,
1709
- // Forward reasoning fields populated by GenerationHandler from AI-SDK
1710
- // reasoning parts (DeepSeek `reasoning_content`, Anthropic thinking,
1711
- // Gemini thought parts, OpenAI o1).
1709
+ // Forward reasoning fields populated by the native generate loop from
1710
+ // vendor reasoning parts (DeepSeek `reasoning_content`, Anthropic
1711
+ // thinking, Gemini thought parts, OpenAI o1).
1712
1712
  reasoning: result.reasoning,
1713
1713
  reasoningTokens: result.reasoningTokens,
1714
1714
  };
@@ -25,12 +25,12 @@ export declare function isGeminiProvider(providerName: string, modelName: string
25
25
  * matched here (different transport, no conflict).
26
26
  *
27
27
  * Being excluded here no longer means the schema is LOST for provider
28
- * "anthropic": GenerationHandler forwards the JSON Schema to the provider via
29
- * `providerOptions.anthropic.finalResultSchema`, and the provider appends an
30
- * additive `final_result` tool (see providers/anthropic/structuredOutput.ts)
31
- * schema enforcement without giving up tool calling. "bedrock" has no such
32
- * handling (it talks to the raw AWS SDK directly, not an ai-sdk provider
33
- * package) and still falls back to text-mode coercion.
28
+ * "anthropic": the client puts the JSON Schema on
29
+ * `providerOptions.anthropic.finalResultSchema` and its `doGenerate` appends
30
+ * an additive `final_result` tool (see providers/anthropic/structuredOutput.ts)
31
+ * schema enforcement without giving up tool calling. "bedrock" has no such
32
+ * handling (it talks to the raw AWS SDK directly) and still falls back to
33
+ * text-mode coercion.
34
34
  */
35
35
  export declare function isNativeAnthropicProvider(providerName: string): boolean;
36
36
  /**
@@ -35,12 +35,12 @@ export function isGeminiProvider(providerName, modelName) {
35
35
  * matched here (different transport, no conflict).
36
36
  *
37
37
  * Being excluded here no longer means the schema is LOST for provider
38
- * "anthropic": GenerationHandler forwards the JSON Schema to the provider via
39
- * `providerOptions.anthropic.finalResultSchema`, and the provider appends an
40
- * additive `final_result` tool (see providers/anthropic/structuredOutput.ts)
41
- * schema enforcement without giving up tool calling. "bedrock" has no such
42
- * handling (it talks to the raw AWS SDK directly, not an ai-sdk provider
43
- * package) and still falls back to text-mode coercion.
38
+ * "anthropic": the client puts the JSON Schema on
39
+ * `providerOptions.anthropic.finalResultSchema` and its `doGenerate` appends
40
+ * an additive `final_result` tool (see providers/anthropic/structuredOutput.ts)
41
+ * schema enforcement without giving up tool calling. "bedrock" has no such
42
+ * handling (it talks to the raw AWS SDK directly) and still falls back to
43
+ * text-mode coercion.
44
44
  */
45
45
  export function isNativeAnthropicProvider(providerName) {
46
46
  return providerName === "anthropic" || providerName === "bedrock";
@@ -96,6 +96,7 @@ export const appendJsonSchemaInstruction = (conversation, schema) => {
96
96
  export async function runNativeGenerateLoop(args, toolExecutionSummaries) {
97
97
  const toolsUsed = [];
98
98
  let text = "";
99
+ let reasoning = "";
99
100
  let finishReason = "stop";
100
101
  let rawFinishReason;
101
102
  let inputTokens = 0;
@@ -175,6 +176,15 @@ export async function runNativeGenerateLoop(args, toolExecutionSummaries) {
175
176
  .filter((p) => p.type === "text" && typeof p.text === "string")
176
177
  .map((p) => p.text)
177
178
  .join("");
179
+ // Reasoner models (DeepSeek `reasoning_content`, gateway `reasoning`,
180
+ // OpenAI o-series) emit reasoning as its own V3 content part. Join it on
181
+ // the same replace-per-step rule as the text so the caller can surface
182
+ // `result.reasoning`; without this the provider builds the part and the
183
+ // loop drops it.
184
+ reasoning = parts
185
+ .filter((p) => p.type === "reasoning" && typeof p.text === "string")
186
+ .map((p) => p.text)
187
+ .join("");
178
188
  const fr = res.finishReason;
179
189
  if (typeof fr === "string") {
180
190
  finishReason = fr;
@@ -287,6 +297,7 @@ export async function runNativeGenerateLoop(args, toolExecutionSummaries) {
287
297
  }
288
298
  return {
289
299
  text,
300
+ ...(reasoning ? { reasoning } : {}),
290
301
  finishReason,
291
302
  ...(rawFinishReason ? { rawFinishReason } : {}),
292
303
  inputTokens,
@@ -16,8 +16,8 @@ export function toNativeToolDeclarations(tools, format) {
16
16
  const input_schema = (rawSchema
17
17
  ? convertZodToJsonSchema(rawSchema)
18
18
  : { type: "object", properties: {} });
19
- // GenerationHandler marks the last tool definition with a cache
20
- // breakpoint when prompt caching is active keep honoring it.
19
+ // Honor a cache breakpoint the caller set on this tool. The direct
20
+ // Anthropic path marks the last tool itself, on the assembled request.
21
21
  const cc = cacheControlOf(tool);
22
22
  const declaration = {
23
23
  name,
@@ -321,7 +321,7 @@ const HAND_DESCRIPTORS = [
321
321
  baseURL: "NVIDIA_NIM_BASE_URL",
322
322
  model: "NVIDIA_NIM_MODEL",
323
323
  },
324
- defaultModel: NvidiaNimModels.LLAMA_3_3_70B_INSTRUCT,
324
+ defaultModel: NvidiaNimModels.GPT_OSS_20B,
325
325
  toolSupport: "native",
326
326
  localRuntime: false,
327
327
  healthCheck: "env-only",
@@ -174,7 +174,10 @@ export class ProviderRegistry {
174
174
  const nimCreds = credentials;
175
175
  const { NvidiaNimProvider } = await import("../providers/nvidiaNim/index.js");
176
176
  return new NvidiaNimProvider(modelName, sdk, undefined, nimCreds);
177
- }, process.env.NVIDIA_NIM_MODEL || NvidiaNimModels.LLAMA_3_3_70B_INSTRUCT, ["nvidia", "nim", "nvidia-nim"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.NVIDIA_NIM));
177
+ }, process.env.NVIDIA_NIM_MODEL ||
178
+ PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.NVIDIA_NIM)
179
+ ?.defaultModel ||
180
+ NvidiaNimModels.GPT_OSS_20B, ["nvidia", "nim", "nvidia-nim"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.NVIDIA_NIM));
178
181
  // Register LM Studio provider (local)
179
182
  ProviderFactory.registerProvider(AIProviderName.LM_STUDIO, async (modelName, _providerName, sdk, _region, credentials) => {
180
183
  const lmStudioCreds = credentials;
package/dist/neurolink.js CHANGED
@@ -4386,7 +4386,7 @@ Current user's request: ${currentInput}`;
4386
4386
  music: textResult.music,
4387
4387
  ppt: textResult.ppt,
4388
4388
  // Forward reasoning/reasoningTokens from the provider layer.
4389
- // BaseProvider's GenerationHandler extracts these from AI-SDK reasoning
4389
+ // The native generate loop extracts these from vendor reasoning
4390
4390
  // parts (DeepSeek's `reasoning_content`, Anthropic thinking blocks,
4391
4391
  // Gemini thought parts, OpenAI o1) and they're declared on
4392
4392
  // `GenerateResult`, but the builder previously dropped them on the
@@ -197,6 +197,7 @@ export class AmazonSageMakerProvider extends BaseProvider {
197
197
  total: loop.inputTokens + loop.outputTokens,
198
198
  },
199
199
  responseTime: Date.now() - startTime,
200
+ ...(loop.reasoning ? { reasoning: loop.reasoning } : {}),
200
201
  toolsUsed: loop.toolsUsed,
201
202
  toolCalls: toolCallsFromSummaries(toolExecutionSummaries),
202
203
  toolExecutions: resolveToolExecutionRecords(options, transformToolExecutions(toolExecutionSummaries)),
@@ -1,9 +1,9 @@
1
1
  import type Anthropic from "@anthropic-ai/sdk";
2
2
  /**
3
3
  * Read an Anthropic cache breakpoint from a message/part/tool carrier.
4
- * MessageBuilder marks system messages (and GenerationHandler marks the last
5
- * tool definition) with `providerOptions.anthropic.cacheControl` the
6
- * AI-SDK-era prompt-caching contract this native path must keep honoring.
4
+ * MessageBuilder marks system messages with
5
+ * `providerOptions.anthropic.cacheControl`; the Anthropic client marks the last
6
+ * tool definition on the assembled request. This reader is what honors both.
7
7
  *
8
8
  * Extracted from anthropic/client.ts so `src/lib/core/nativeToolFormat.ts`
9
9
  * can share it without importing the provider client (which would create a
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Read an Anthropic cache breakpoint from a message/part/tool carrier.
3
- * MessageBuilder marks system messages (and GenerationHandler marks the last
4
- * tool definition) with `providerOptions.anthropic.cacheControl` the
5
- * AI-SDK-era prompt-caching contract this native path must keep honoring.
3
+ * MessageBuilder marks system messages with
4
+ * `providerOptions.anthropic.cacheControl`; the Anthropic client marks the last
5
+ * tool definition on the assembled request. This reader is what honors both.
6
6
  *
7
7
  * Extracted from anthropic/client.ts so `src/lib/core/nativeToolFormat.ts`
8
8
  * can share it without importing the provider client (which would create a
@@ -1027,8 +1027,8 @@ export class AnthropicProvider extends BaseProvider {
1027
1027
  let tools = (options.tools ?? [])
1028
1028
  .filter((t) => t.type === "function")
1029
1029
  .map((t) => {
1030
- // GenerationHandler marks the last tool definition with a cache
1031
- // breakpoint when prompt caching is active keep honoring it.
1030
+ // Honor a cache breakpoint the caller set on this tool. When no
1031
+ // tool carries one, the last tool is marked further below.
1032
1032
  const cc = cacheControlOf(t);
1033
1033
  return {
1034
1034
  name: t.name,
@@ -1069,10 +1069,10 @@ export class AnthropicProvider extends BaseProvider {
1069
1069
  }
1070
1070
  // Additive structured output: when the caller wants a schema AND real
1071
1071
  // tools, the forced-json path above cannot be used (it replaces the
1072
- // tools array), and the AI-SDK experimental_output path is excluded
1073
- // for this surface by structuredOutputPolicy. GenerationHandler hands
1074
- // the JSON Schema down here instead, and we APPEND a `final_result`
1075
- // tool — tool_choice stays auto, so every real tool keeps working and
1072
+ // tools array), and structured output is excluded for this surface
1073
+ // by structuredOutputPolicy. The schema arrives instead on
1074
+ // `providerOptions.anthropic.finalResultSchema` and we APPEND a
1075
+ // `final_result` tool — tool_choice stays auto, so every real tool keeps working and
1076
1076
  // the model self-selects final_result when it is ready to answer.
1077
1077
  const finalResultSchema = options.providerOptions?.anthropic
1078
1078
  ?.finalResultSchema;
@@ -1087,9 +1087,26 @@ export class AnthropicProvider extends BaseProvider {
1087
1087
  }
1088
1088
  // Extended thinking passthrough (providerOptions.anthropic.thinking).
1089
1089
  const thinking = options.providerOptions?.anthropic?.thinking;
1090
+ // Close the stable prefix with a breakpoint on the LAST tool. Tool
1091
+ // definitions sit between the system prompt and the conversation and
1092
+ // rarely change, so without this the whole tools block is re-billed
1093
+ // every turn. Applied after every tool mutation above (including the
1094
+ // appended final_result tool) so the marker really is last, and before
1095
+ // the count below so the history budget accounts for it. A caller that
1096
+ // marked a tool itself wins.
1097
+ if (tools && tools.length > 0) {
1098
+ const alreadyMarked = tools.some((t) => cacheControlOf(t));
1099
+ if (!alreadyMarked) {
1100
+ const last = tools[tools.length - 1];
1101
+ tools = [
1102
+ ...tools.slice(0, -1),
1103
+ { ...last, cache_control: { type: "ephemeral" } },
1104
+ ];
1105
+ }
1106
+ }
1090
1107
  // Prompt-cache parity with the native Vertex+Claude path: upstream
1091
- // layers mark only the stable prefix (system via MessageBuilder,
1092
- // last tool via GenerationHandler) — the growing conversation
1108
+ // layers mark the stable prefix (system via MessageBuilder, and the
1109
+ // last tool just above) — the growing conversation
1093
1110
  // history has no breakpoint, so on every turn it falls after the
1094
1111
  // last marker and is re-billed as fresh input. Add rolling history
1095
1112
  // breakpoints in whatever budget remains under Anthropic's
@@ -1469,6 +1486,7 @@ export class AnthropicProvider extends BaseProvider {
1469
1486
  ...(loop.rawFinishReason
1470
1487
  ? { rawFinishReason: loop.rawFinishReason }
1471
1488
  : {}),
1489
+ ...(loop.reasoning ? { reasoning: loop.reasoning } : {}),
1472
1490
  usage: {
1473
1491
  input: loop.inputTokens,
1474
1492
  output: loop.outputTokens,
@@ -44,7 +44,7 @@ export declare class ConfiguredOpenAICompatProvider extends OpenAIChatCompletion
44
44
  * a `tools` array — Mancer's free model rejects one with 400 — so the
45
45
  * declaration wins here and the registry is only consulted otherwise.
46
46
  * Like the other entry-reading overrides above, this runs only after
47
- * construction: BaseProvider merely closes over it for GenerationHandler.
47
+ * construction: BaseProvider merely closes over it.
48
48
  */
49
49
  supportsTools(): boolean;
50
50
  protected adjustRequestBody(body: OpenAICompatChatRequest, modelId: string): OpenAICompatChatRequest;
@@ -94,7 +94,7 @@ export class ConfiguredOpenAICompatProvider extends OpenAIChatCompletionsProvide
94
94
  * a `tools` array — Mancer's free model rejects one with 400 — so the
95
95
  * declaration wins here and the registry is only consulted otherwise.
96
96
  * Like the other entry-reading overrides above, this runs only after
97
- * construction: BaseProvider merely closes over it for GenerationHandler.
97
+ * construction: BaseProvider merely closes over it.
98
98
  */
99
99
  supportsTools() {
100
100
  if (this.entry.supportsTools === false) {
@@ -1307,9 +1307,8 @@ export class GoogleAIStudioProvider extends BaseProvider {
1307
1307
  try {
1308
1308
  // Wrap in `neurolink.executeGeneration` so the observability span
1309
1309
  // chain (Test: Generate Span Chain) sees a third inner span on the
1310
- // native @google/genai path Pipeline A providers get this from
1311
- // GenerationHandler.executeGeneration; the native path bypasses
1312
- // GenerationHandler so we add the span here.
1310
+ // native @google/genai path. This provider overrides generate() instead
1311
+ // of using BaseProvider's shared flow, so the span is added here.
1313
1312
  let result = await withSpan({
1314
1313
  name: "neurolink.executeGeneration",
1315
1314
  tracer: tracers.provider,
@@ -5245,8 +5245,8 @@ export class GoogleVertexProvider extends BaseProvider {
5245
5245
  // Wrap the actual native generate call in `neurolink.executeGeneration`
5246
5246
  // so the observability span chain (tested by
5247
5247
  // "Tracing: Generate Span Chain") sees a third inner span on the
5248
- // native @google/genai / @anthropic-ai/vertex-sdk path — Pipeline A
5249
- // gets this for free from GenerationHandler.executeGeneration.
5248
+ // native @google/genai / @anthropic-ai/vertex-sdk path. This
5249
+ // provider overrides generate(), so the span is added here.
5250
5250
  result = await withSpan({
5251
5251
  name: "neurolink.executeGeneration",
5252
5252
  tracer: tracers.provider,
@@ -5,6 +5,7 @@ import { logger } from "../../utils/logger.js";
5
5
  import { redactUrlCredentials } from "../../utils/logSanitize.js";
6
6
  import { createNvidiaNimConfig, getProviderModel, validateApiKey, } from "../../utils/providerConfig.js";
7
7
  import { OpenAIChatCompletionsProvider } from "../openaiChatCompletionsBase.js";
8
+ import { PROVIDER_DESCRIPTORS_BY_NAME } from "../../factories/providerDescriptors.js";
8
9
  /**
9
10
  * Decide whether a NIM 400 response body is a rejection of the named
10
11
  * field (as opposed to an unrelated 400 that happens to mention the
@@ -136,7 +137,16 @@ const getNimApiKey = () => {
136
137
  return validateApiKey(createNvidiaNimConfig());
137
138
  };
138
139
  const getDefaultNimModel = () => {
139
- return getProviderModel("NVIDIA_NIM_MODEL", NvidiaNimModels.LLAMA_3_3_70B_INSTRUCT);
140
+ // NVIDIA retired meta/llama-3.3-70b-instruct upstream on 2026-08-26, so this
141
+ // fallback answered "no longer available" for anyone who selected nvidia-nim
142
+ // without naming a model. gpt-oss-20b is on the current roster and was
143
+ // probed for text, streaming, tool calling and structured output.
144
+ // Read the descriptor rather than repeating the literal. Review on this PR
145
+ // pointed out the default lived in four places and that changing only some
146
+ // of them is a no-op — which happened twice while tracking this down. The
147
+ // descriptor is the Factory+Registry convention's source of truth.
148
+ return getProviderModel("NVIDIA_NIM_MODEL", PROVIDER_DESCRIPTORS_BY_NAME.get("nvidia-nim")
149
+ ?.defaultModel ?? NvidiaNimModels.GPT_OSS_20B);
140
150
  };
141
151
  /**
142
152
  * NVIDIA NIM Provider — native HTTP+SSE, no AI SDK.
@@ -76,13 +76,13 @@ export declare abstract class OpenAIChatCompletionsProvider extends BaseProvider
76
76
  protected adjustResponseFormat(rf: OpenAICompatResponseFormat | undefined, _modelId: string): OpenAICompatResponseFormat | undefined;
77
77
  /**
78
78
  * When true (default), `response_format` is NOT sent on requests that carry
79
- * tools. The AI SDK sets responseFormat on EVERY step of a tool loop, and
80
- * generic/proxy backends (LiteLLM→vllm/GLM, openai-compatible, local
79
+ * tools. The generate loop sets responseFormat on EVERY step of a tool
80
+ * loop, and generic/proxy backends (LiteLLM→vllm/GLM, openai-compatible, local
81
81
  * servers) may silently honor it over tool calling — answering with
82
82
  * final-shape JSON on step 1 instead of running the agentic loop. No error
83
83
  * is raised, so the runtime tools↔schema conflict detector cannot catch it.
84
- * The schema is still enforced post-hoc (GenerationHandler coerces the final
85
- * text against it) — the same contract as the Gemini tools↔schema exclusion.
84
+ * The schema is still enforced post-hoc (`coerceJsonToSchema` runs against
85
+ * the final text) — the same contract as the Gemini tools↔schema exclusion.
86
86
  * Mirrors the streaming path, which never sends response_format.
87
87
  *
88
88
  * Backends with first-party support for tools + json_schema in one request
@@ -199,13 +199,13 @@ export class OpenAIChatCompletionsProvider extends BaseProvider {
199
199
  }
200
200
  /**
201
201
  * When true (default), `response_format` is NOT sent on requests that carry
202
- * tools. The AI SDK sets responseFormat on EVERY step of a tool loop, and
203
- * generic/proxy backends (LiteLLM→vllm/GLM, openai-compatible, local
202
+ * tools. The generate loop sets responseFormat on EVERY step of a tool
203
+ * loop, and generic/proxy backends (LiteLLM→vllm/GLM, openai-compatible, local
204
204
  * servers) may silently honor it over tool calling — answering with
205
205
  * final-shape JSON on step 1 instead of running the agentic loop. No error
206
206
  * is raised, so the runtime tools↔schema conflict detector cannot catch it.
207
- * The schema is still enforced post-hoc (GenerationHandler coerces the final
208
- * text against it) — the same contract as the Gemini tools↔schema exclusion.
207
+ * The schema is still enforced post-hoc (`coerceJsonToSchema` runs against
208
+ * the final text) — the same contract as the Gemini tools↔schema exclusion.
209
209
  * Mirrors the streaming path, which never sends response_format.
210
210
  *
211
211
  * Backends with first-party support for tools + json_schema in one request
@@ -709,7 +709,7 @@ export class OpenAIChatCompletionsProvider extends BaseProvider {
709
709
  const content = [];
710
710
  // Reasoner-model output (DeepSeek `reasoning_content`, gateway
711
711
  // `reasoning`) becomes a V3 reasoning part ahead of the text part —
712
- // GenerationHandler joins reasoning parts into `result.reasoning`.
712
+ // the native generate loop joins those parts into `result.reasoning`.
713
713
  // `||` so an empty-string reasoning_content falls through to a
714
714
  // non-empty `reasoning` field instead of shadowing it.
715
715
  const reasoningText = choice?.message?.reasoning_content || choice?.message?.reasoning;
@@ -921,11 +921,11 @@ export class OpenAIChatCompletionsProvider extends BaseProvider {
921
921
  // words instead: drop `response_format` and spell the JSON Schema into the
922
922
  // system prompt, letting coerceJsonToSchema recover the object from text.
923
923
  //
924
- // Ported from GenerationHandler's `promptJsonInstruction` fallback, which
925
- // runs this on the ai-package path. That path is unreachable for every
926
- // provider driven by this loop GMI Cloud's MiniMax endpoint, the one it
927
- // was written for, is a Tier-2 catalog provider on this very base class —
928
- // so without this the recovery would simply not happen for it.
924
+ // Ported from GenerationHandler's `promptJsonInstruction` fallback on the
925
+ // ai-package path, which has since been deleted — GMI Cloud's MiniMax
926
+ // endpoint, the one it was written for, is a Tier-2 catalog provider on
927
+ // this very base class, so without this the recovery would simply not
928
+ // happen for it.
929
929
  let loop;
930
930
  try {
931
931
  loop = await runLoop(conversation, responseFormat);
@@ -991,6 +991,7 @@ export class OpenAIChatCompletionsProvider extends BaseProvider {
991
991
  : {}),
992
992
  },
993
993
  responseTime: Date.now() - startTime,
994
+ ...(loop.reasoning ? { reasoning: loop.reasoning } : {}),
994
995
  toolsUsed,
995
996
  toolCalls: toolCallsFromSummaries(toolExecutionSummaries),
996
997
  toolExecutions: resolveToolExecutionRecords(options, transformToolExecutions(toolExecutionSummaries)),
@@ -219,28 +219,6 @@ export type BudgetCheckResult = {
219
219
  fileAttachments: number;
220
220
  };
221
221
  };
222
- /**
223
- * Configuration for the per-step context budget guard that compacts the
224
- * AI-SDK tool loop's messages before they overflow the model window
225
- * (context/stepBudgetGuard.ts).
226
- */
227
- export type StepBudgetGuardConfig = {
228
- provider: string;
229
- model?: string;
230
- /** The caller's requested output budget (reserved out of the window). */
231
- maxTokens?: number;
232
- /** Static token cost of the hoisted system prompt + tool definitions. */
233
- fixedOverheadTokens?: number;
234
- /**
235
- * Dynamic overhead resolver, re-evaluated on EVERY guard invocation. Takes
236
- * precedence over `fixedOverheadTokens`. Use when the tool set can grow
237
- * mid-loop (search_tools hydration) so newly added definitions count toward
238
- * the budget.
239
- */
240
- getFixedOverheadTokens?: () => number;
241
- /** Override the trigger ratio; defaults to DEFAULT_CONTEXT_GUARD_RATIO. */
242
- thresholdRatio?: number;
243
- };
244
222
  /** Parameters for budget checking. */
245
223
  export type BudgetCheckParams = {
246
224
  provider: string;
@@ -1567,23 +1567,6 @@ export type ModelAliasConfig = {
1567
1567
  export type GenerateOptionsNormalized = GenerateOptions & {
1568
1568
  input: NonNullable<GenerateOptions["input"]>;
1569
1569
  };
1570
- /**
1571
- * Per-call configuration for GenerationHandler's AI-SDK loop invocation,
1572
- * shared by the initial call and every fallback retry so they cannot drift.
1573
- */
1574
- export type GenerationCallConfig = {
1575
- shouldUseTools: boolean;
1576
- includeStructuredOutput: boolean;
1577
- /** Anchor for the turn deadline — the ORIGINAL executeGeneration start,
1578
- * shared across fallback/provider retries so they can't refresh the
1579
- * wall-clock budget. */
1580
- turnStartMs: number;
1581
- /** Structured-output fallback retry: also spell the JSON Schema out in the
1582
- * system prompt, for vendors that ignore `response_format`. */
1583
- promptJsonInstruction?: boolean;
1584
- /** Set on the single toolChoice:"none" re-ask so it can never recurse. */
1585
- isToolReask?: boolean;
1586
- };
1587
1570
  /**
1588
1571
  * Inputs to the shared native generate loop (`core/nativeGenerateLoop.ts`).
1589
1572
  * One loop serves every provider whose delegating model exposes a v3-shaped
@@ -1611,6 +1594,8 @@ export type NativeGenerateLoopArgs = {
1611
1594
  };
1612
1595
  export type NativeGenerateLoopResult = {
1613
1596
  text: string;
1597
+ /** Joined reasoning content parts from the final step, when the vendor sent any. */
1598
+ reasoning?: string;
1614
1599
  finishReason: string;
1615
1600
  rawFinishReason?: string;
1616
1601
  inputTokens: number;
@@ -5,7 +5,7 @@ import type { UnknownRecord, JsonValue, StreamingCapability } from "./common.js"
5
5
  import type { NeuroLink } from "../neurolink.js";
6
6
  import { AIProviderName, AnthropicModels, BedrockModels, DeepSeekModels, GoogleAIModels, LlamaCppModels, LMStudioModels, NvidiaNimModels, OpenAIModels, VertexModels } from "../constants/enums.js";
7
7
  import type { ValidationSchema } from "./aliases.js";
8
- import type { EnhancedGenerateResult, GenerateResult, TextGenerationOptions } from "./generate.js";
8
+ import type { EnhancedGenerateResult, TextGenerationOptions } from "./generate.js";
9
9
  import type { MultimodalAudioEntry } from "./file.js";
10
10
  import type { StreamOptions, StreamResult } from "./stream.js";
11
11
  import type { ProviderError, ProviderErrorRule } from "./errors.js";
@@ -824,20 +824,6 @@ export type ProviderCapability = "text-generation" | "streaming" | "tool-calling
824
824
  * Extended tool type that combines AI SDK tools with external MCP tool info
825
825
  */
826
826
  export type ExtendedTool = Tool & Partial<ExternalMCPToolInfo>;
827
- /**
828
- * AI SDK generate result with steps support (extends GenerateResult)
829
- */
830
- export type AISDKGenerateResult = GenerateResult & {
831
- steps?: Array<{
832
- toolCalls?: Array<{
833
- toolName?: string;
834
- name?: string;
835
- [key: string]: unknown;
836
- }>;
837
- [key: string]: unknown;
838
- }>;
839
- [key: string]: unknown;
840
- };
841
827
  /**
842
828
  * Bedrock tool usage structure
843
829
  */
@@ -1852,18 +1838,6 @@ export type LanguageModelObject = {
1852
1838
  readonly modelId: string;
1853
1839
  readonly provider: string;
1854
1840
  };
1855
- /** Step finish event shape for multi-step generation. */
1856
- export type StepFinishEvent = {
1857
- readonly toolCalls: ReadonlyArray<unknown>;
1858
- readonly toolResults: ReadonlyArray<unknown>;
1859
- readonly text: string;
1860
- readonly finishReason: string;
1861
- readonly usage: {
1862
- inputTokens?: number;
1863
- outputTokens?: number;
1864
- };
1865
- [key: string]: unknown;
1866
- };
1867
1841
  /**
1868
1842
  * Represents an AI SDK Tool that may carry a legacy `parameters` field
1869
1843
  * (from AI SDK v3/v4) in addition to the current `inputSchema`.
@@ -17,11 +17,11 @@ export declare const ANTHROPIC_MAX_CACHE_BREAKPOINTS = 4;
17
17
  export declare function applyVertexAnthropicCacheBreakpoints(input: VertexAnthropicCacheInput): VertexAnthropicCacheOutput;
18
18
  /**
19
19
  * Count the `cache_control` markers already present on a request. The direct
20
- * Anthropic path (AI-SDK pipeline) arrives with markers the upstream layers
21
- * placed — MessageBuilder tags the system prompt, GenerationHandler tags the
22
- * last tool definition, and message content blocks may carry translated
23
- * AI-SDK markers. Anthropic rejects requests with more than four markers, so
24
- * any additional history breakpoints must fit in the remaining budget.
20
+ * Anthropic path arrives with markers the upstream layers placed —
21
+ * MessageBuilder tags the system prompt, the client tags the last tool
22
+ * definition, and message content blocks may carry their own. Anthropic
23
+ * rejects requests with more than four markers, so any additional history
24
+ * breakpoints must fit in the remaining budget.
25
25
  */
26
26
  export declare function countAnthropicCacheMarkers(input: {
27
27
  system?: string | ReadonlyArray<{
@@ -35,7 +35,7 @@ export declare function countAnthropicCacheMarkers(input: {
35
35
  /**
36
36
  * Rolling history breakpoints for request paths whose stable-prefix markers
37
37
  * are managed upstream (direct Anthropic: system via MessageBuilder, last
38
- * tool via GenerationHandler). Marks the last content block of up to `budget`
38
+ * tool via the provider client). Marks the last content block of up to `budget`
39
39
  * tail messages; a tail block that already carries a marker is left as-is
40
40
  * without consuming budget (it already serves as that breakpoint). Pure —
41
41
  * the input array is cloned, never mutated.
@@ -63,11 +63,11 @@ export function applyVertexAnthropicCacheBreakpoints(input) {
63
63
  }
64
64
  /**
65
65
  * Count the `cache_control` markers already present on a request. The direct
66
- * Anthropic path (AI-SDK pipeline) arrives with markers the upstream layers
67
- * placed — MessageBuilder tags the system prompt, GenerationHandler tags the
68
- * last tool definition, and message content blocks may carry translated
69
- * AI-SDK markers. Anthropic rejects requests with more than four markers, so
70
- * any additional history breakpoints must fit in the remaining budget.
66
+ * Anthropic path arrives with markers the upstream layers placed —
67
+ * MessageBuilder tags the system prompt, the client tags the last tool
68
+ * definition, and message content blocks may carry their own. Anthropic
69
+ * rejects requests with more than four markers, so any additional history
70
+ * breakpoints must fit in the remaining budget.
71
71
  */
72
72
  export function countAnthropicCacheMarkers(input) {
73
73
  let count = 0;
@@ -87,7 +87,7 @@ export function countAnthropicCacheMarkers(input) {
87
87
  /**
88
88
  * Rolling history breakpoints for request paths whose stable-prefix markers
89
89
  * are managed upstream (direct Anthropic: system via MessageBuilder, last
90
- * tool via GenerationHandler). Marks the last content block of up to `budget`
90
+ * tool via the provider client). Marks the last content block of up to `budget`
91
91
  * tail messages; a tail block that already carries a marker is left as-is
92
92
  * without consuming budget (it already serves as that breakpoint). Pure —
93
93
  * the input array is cloned, never mutated.
@@ -15,8 +15,9 @@ export declare function schemaAccepts(schema: ValidationSchema | undefined, valu
15
15
  * object/array case is handled by `coerceJsonToSchema`; this covers the
16
16
  * residual scalar root after that path returns null. Encapsulates the JSON
17
17
  * parsing, the empty-string normalization, and the `schemaAccepts` gate so the
18
- * same policy cannot drift between consumers (`neurolink.recoverStructuredData`
19
- * and `GenerationHandler.coerceTextMode`).
18
+ * same policy cannot drift between consumers. `neurolink.recoverStructuredData`
19
+ * is the only one left; `GenerationHandler.coerceTextMode` was the other until
20
+ * the ai-package path was deleted.
20
21
  */
21
22
  export declare function recoverScalarRoot(text: string, schema: ValidationSchema | undefined): ScalarRecoveryDecision;
22
23
  /**
@@ -44,8 +44,9 @@ export function schemaAccepts(schema, value) {
44
44
  * object/array case is handled by `coerceJsonToSchema`; this covers the
45
45
  * residual scalar root after that path returns null. Encapsulates the JSON
46
46
  * parsing, the empty-string normalization, and the `schemaAccepts` gate so the
47
- * same policy cannot drift between consumers (`neurolink.recoverStructuredData`
48
- * and `GenerationHandler.coerceTextMode`).
47
+ * same policy cannot drift between consumers. `neurolink.recoverStructuredData`
48
+ * is the only one left; `GenerationHandler.coerceTextMode` was the other until
49
+ * the ai-package path was deleted.
49
50
  */
50
51
  export function recoverScalarRoot(text, schema) {
51
52
  try {