@juspay/neurolink 12.11.3 → 12.12.0

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 (52) hide show
  1. package/CHANGELOG.md +3 -4
  2. package/dist/browser/neurolink.min.js +533 -581
  3. package/dist/constants/enums.d.ts +13 -0
  4. package/dist/constants/enums.js +14 -0
  5. package/dist/core/baseProvider.d.ts +71 -3
  6. package/dist/core/baseProvider.js +152 -44
  7. package/dist/core/modules/GenerationHandler.d.ts +22 -24
  8. package/dist/core/modules/GenerationHandler.js +28 -463
  9. package/dist/core/nativeGenerateLoop.d.ts +35 -0
  10. package/dist/core/nativeGenerateLoop.js +261 -0
  11. package/dist/files/fileTools.d.ts +5 -5
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.js +4 -0
  14. package/dist/middleware/builtin/guardrails.d.ts +0 -5
  15. package/dist/middleware/builtin/guardrails.js +33 -5
  16. package/dist/middleware/factory.js +1 -1
  17. package/dist/middleware/wrapLanguageModel.d.ts +18 -0
  18. package/dist/middleware/wrapLanguageModel.js +53 -0
  19. package/dist/processors/media/AudioProcessor.js +46 -11
  20. package/dist/providers/amazonSagemaker.d.ts +17 -1
  21. package/dist/providers/amazonSagemaker.js +110 -0
  22. package/dist/providers/anthropic/client.d.ts +11 -0
  23. package/dist/providers/anthropic/client.js +148 -1
  24. package/dist/providers/catalog/index.generated.d.ts +1 -1
  25. package/dist/providers/catalog/index.generated.js +3 -0
  26. package/dist/providers/catalog/loader.js +1 -0
  27. package/dist/providers/catalog/mancer.json +192 -0
  28. package/dist/providers/configuredOpenAICompat.d.ts +11 -0
  29. package/dist/providers/configuredOpenAICompat.js +16 -0
  30. package/dist/providers/googleVertex/client.d.ts +0 -9
  31. package/dist/providers/googleVertex/client.js +0 -33
  32. package/dist/providers/openaiChatCompletionsBase.d.ts +21 -1
  33. package/dist/providers/openaiChatCompletionsBase.js +178 -0
  34. package/dist/providers/providerTypeUtils.d.ts +1 -2
  35. package/dist/providers/providerTypeUtils.js +5 -1
  36. package/dist/types/aiCompat.d.ts +485 -0
  37. package/dist/types/aiCompat.js +17 -0
  38. package/dist/types/conversation.d.ts +1 -1
  39. package/dist/types/generate.d.ts +52 -0
  40. package/dist/types/middleware.d.ts +3 -6
  41. package/dist/types/providerCatalog.generated.d.ts +2 -2
  42. package/dist/types/providers.d.ts +14 -1
  43. package/dist/types/tools.d.ts +2 -2
  44. package/dist/utils/generationErrors.d.ts +78 -6
  45. package/dist/utils/generationErrors.js +114 -6
  46. package/dist/utils/nativeSingleShot.d.ts +3 -0
  47. package/dist/utils/nativeSingleShot.js +83 -0
  48. package/dist/utils/tool.d.ts +30 -5
  49. package/dist/utils/tool.js +43 -5
  50. package/package.json +3 -6
  51. package/dist/utils/generation.d.ts +0 -8
  52. package/dist/utils/generation.js +0 -8
@@ -19,7 +19,7 @@
19
19
  */
20
20
  import type { AIProviderName } from "../constants/enums.js";
21
21
  import { BaseProvider } from "../core/baseProvider.js";
22
- import type { LanguageModel, OpenAICompatBuildBodyArgs, OpenAICompatChatMessage, OpenAICompatChatRequest, OpenAICompatChatTool, OpenAICompatResponseFormat, OpenAICompatStreamLifecycleListeners, Schema, StreamOptions, StreamResult, ZodUnknownSchema } from "../types/index.js";
22
+ import type { LanguageModel, OpenAICompatBuildBodyArgs, OpenAICompatChatMessage, OpenAICompatChatRequest, OpenAICompatChatTool, OpenAICompatResponseFormat, OpenAICompatStreamLifecycleListeners, Schema, EnhancedGenerateResult, TextGenerationOptions, ValidationSchema, StreamOptions, StreamResult, ZodUnknownSchema } from "../types/index.js";
23
23
  /**
24
24
  * Abstract HTTP+SSE provider for OpenAI chat-completions-shaped endpoints.
25
25
  */
@@ -227,6 +227,26 @@ export declare abstract class OpenAIChatCompletionsProvider extends BaseProvider
227
227
  * streamText, no AI SDK orchestrator. Tool calls, multi-step loops,
228
228
  * telemetry, abort handling all inline.
229
229
  */
230
+ /**
231
+ * Native non-streaming generate.
232
+ *
233
+ * Drives the SAME `doGenerate` the ai loop drove — `buildDelegatingModel`'s,
234
+ * reached through `getAISDKModel()` — and supplies only the multi-step tool
235
+ * iteration around it. That matters: `doGenerate` is where the JSON-versus-SSE
236
+ * wire choice lives (`useStreamingWireForGenerate()`, false by default), along
237
+ * with the 400 retry, the context-overflow refit and the invalid-model
238
+ * fallback. An earlier attempt ran generate through the STREAMING loop
239
+ * instead and silently began sending `stream: true` on a path that had always
240
+ * sent plain JSON; ten providers returned empty content against a
241
+ * non-streaming body and a stream-rejecting backend failed outright. Loop
242
+ * around doGenerate, never around streamOneStep.
243
+ *
244
+ * Tool turns are appended in the message-builder shape, which
245
+ * `messageBuilderToOpenAI` already round-trips: an assistant message carrying
246
+ * `tool-call` parts, then one `tool` message of `tool-result` parts.
247
+ */
248
+ generate(optionsOrPrompt: TextGenerationOptions | string, analysisSchema?: ValidationSchema): Promise<EnhancedGenerateResult | null>;
249
+ private executeNativeGenerate;
230
250
  protected executeStream(options: StreamOptions, _analysisSchema?: ZodUnknownSchema | Schema<unknown>): Promise<StreamResult>;
231
251
  private runStreamLoop;
232
252
  private streamOneStep;
@@ -32,9 +32,14 @@ import { NoOutputGeneratedError } from "../utils/generationErrors.js";
32
32
  import { buildNoOutputSentinel, stampNoOutputSpan, } from "../utils/noOutputSentinel.js";
33
33
  import { composeAbortSignalsScoped, createTimeoutController, mergeAbortSignals, } from "../utils/timeout.js";
34
34
  import { emitToolEndFromStepFinish } from "../utils/toolEndEmitter.js";
35
+ import { resolveRequestKind } from "../core/resolveRequestKind.js";
36
+ import { appendJsonSchemaInstruction, hasNativeDoGenerate, runNativeGenerateLoop, } from "../core/nativeGenerateLoop.js";
37
+ import { resolveToolExecutionRecords } from "../core/toolExecutionRecorder.js";
38
+ import { convertZodToJsonSchema } from "../utils/schemaConversion.js";
35
39
  import { resolveToolChoice } from "../utils/toolChoice.js";
36
40
  import { transformToolExecutions } from "../utils/transformationUtils.js";
37
41
  import { withProviderRetry } from "../utils/providerRetry.js";
42
+ import { isSchemaComplexityError, isToolsSchemaConflictError, } from "../core/modules/structuredOutputPolicy.js";
38
43
  import { resolveDeferredTool } from "../tools/toolDiscovery.js";
39
44
  import { buildAPIError, buildBody, buildToolsForOpenAI, buildWireToolNameMaps, createDeferredAnalytics, ensureJsonWordInBody, estimateWireTokens, mapNeuroLinkToolChoice, mergeUsage, messageBuilderToOpenAI, parseSSEStream, stringifyToolOutput, stripTrailingSlash, v3ResponseFormatToOpenAI, v3ToolChoiceToOpenAI, v3ToolsToOpenAI, } from "./openaiChatCompletionsClient.js";
40
45
  import { createStreamChannel } from "../core/streamChannel.js";
@@ -707,6 +712,179 @@ export class OpenAIChatCompletionsProvider extends BaseProvider {
707
712
  * streamText, no AI SDK orchestrator. Tool calls, multi-step loops,
708
713
  * telemetry, abort handling all inline.
709
714
  */
715
+ /**
716
+ * Native non-streaming generate.
717
+ *
718
+ * Drives the SAME `doGenerate` the ai loop drove — `buildDelegatingModel`'s,
719
+ * reached through `getAISDKModel()` — and supplies only the multi-step tool
720
+ * iteration around it. That matters: `doGenerate` is where the JSON-versus-SSE
721
+ * wire choice lives (`useStreamingWireForGenerate()`, false by default), along
722
+ * with the 400 retry, the context-overflow refit and the invalid-model
723
+ * fallback. An earlier attempt ran generate through the STREAMING loop
724
+ * instead and silently began sending `stream: true` on a path that had always
725
+ * sent plain JSON; ten providers returned empty content against a
726
+ * non-streaming body and a stream-rejecting backend failed outright. Loop
727
+ * around doGenerate, never around streamOneStep.
728
+ *
729
+ * Tool turns are appended in the message-builder shape, which
730
+ * `messageBuilderToOpenAI` already round-trips: an assistant message carrying
731
+ * `tool-call` parts, then one `tool` message of `tool-result` parts.
732
+ */
733
+ async generate(optionsOrPrompt, analysisSchema) {
734
+ await this.ensureModelLimits();
735
+ const options = this.normalizeTextOptions(optionsOrPrompt);
736
+ if (resolveRequestKind(options, this.modelName) !== "text") {
737
+ return super.generate(options, analysisSchema);
738
+ }
739
+ this.validateOptions(options);
740
+ const mergedTools = await this.getToolsForStream(options);
741
+ // Reuse BaseProvider's invalid-model fallback. Overriding generate() skips
742
+ // it otherwise, and a retired default stops degrading to the next live
743
+ // model in the catalog entry.
744
+ const callerOwnsFallback = "disableInternalFallback" in options &&
745
+ options.disableInternalFallback === true;
746
+ // The native loop bypasses BaseProvider.executeGeneration, so the turn
747
+ // budget has to be composed here or it stops existing for this provider.
748
+ return this.runGenerateWithModelFallback(() => this.withTurnTimeout({ ...options, tools: mergedTools }, this.getDescriptorGenerateMs(), (timedOptions) => this.executeNativeGenerate(timedOptions)), callerOwnsFallback);
749
+ }
750
+ async executeNativeGenerate(options) {
751
+ const startTime = Date.now();
752
+ const modelId = await this.resolveModelName();
753
+ // Middleware must wrap the model here. The native loop bypasses
754
+ // BaseProvider.executeGeneration, and with it the only place middleware was
755
+ // ever applied — a probe showed a caller's wrapGenerate running zero times
756
+ // on every native provider while their onFinish still fired, because
757
+ // onFinish had been special-cased and nothing else had.
758
+ const model = await this.getAISDKModelWithMiddleware(options);
759
+ // Runtime guard rather than an assertion: `LanguageModel` is a union that
760
+ // includes a bare string id, and a double assertion through unknown is
761
+ // banned by Critical Rule 14.
762
+ if (!hasNativeDoGenerate(model)) {
763
+ throw this.handleProviderError(new Error(`${this.providerName}: model handle exposes no doGenerate()`));
764
+ }
765
+ const doGenerate = model.doGenerate.bind(model);
766
+ const shouldUseTools = !options.disableTools && this.supportsTools();
767
+ const toolsRecord = shouldUseTools
768
+ ? options.tools || (await this.getAllTools())
769
+ : {};
770
+ // v3 tool shape — the same one doGenerate already converts internally.
771
+ const v3Tools = shouldUseTools
772
+ ? Object.entries(toolsRecord).map(([name, t]) => {
773
+ const tool = t;
774
+ return {
775
+ type: "function",
776
+ name,
777
+ description: tool.description ?? "",
778
+ inputSchema: (tool.inputSchema
779
+ ? convertZodToJsonSchema(tool.inputSchema)
780
+ : { type: "object", properties: {} }),
781
+ };
782
+ })
783
+ : undefined;
784
+ const hasTools = !!v3Tools && v3Tools.length > 0;
785
+ // Structured output rides response_format, which is what Output.object did
786
+ // on the ai path. Suppressed where the provider says the combination with
787
+ // tools is rejected.
788
+ const responseFormat = options.schema && !(hasTools && this.suppressResponseFormatWithTools())
789
+ ? {
790
+ type: "json",
791
+ schema: convertZodToJsonSchema(options.schema),
792
+ }
793
+ : undefined;
794
+ const conversation = (await this.buildMessagesForStream(options));
795
+ const toolExecutionSummaries = [];
796
+ const runLoop = (conv, format) => runNativeGenerateLoop({
797
+ doGenerate,
798
+ conversation: conv,
799
+ ...(v3Tools ? { tools: v3Tools } : {}),
800
+ toolsRecord,
801
+ ...(hasTools && options.toolChoice
802
+ ? { toolChoice: resolveToolChoice(options, toolsRecord, true) }
803
+ : {}),
804
+ // The per-call `timeout` keeps its per-MODEL-CALL meaning once
805
+ // `turnTimeoutMs` owns the whole-turn deadline, and it reaches the
806
+ // model layer only through this channel. Without it each step fell
807
+ // back to the provider default, so a caller asking for a short
808
+ // per-call timeout got the default on every request.
809
+ ...(typeof options.timeout === "number"
810
+ ? {
811
+ providerOptions: {
812
+ neurolink: { timeoutMs: options.timeout },
813
+ },
814
+ }
815
+ : {}),
816
+ ...(format ? { responseFormat: format } : {}),
817
+ maxSteps: options.maxSteps || DEFAULT_MAX_STEPS,
818
+ ...(options.maxTokens ? { maxOutputTokens: options.maxTokens } : {}),
819
+ ...(options.temperature !== undefined
820
+ ? { temperature: options.temperature }
821
+ : {}),
822
+ ...(options.abortSignal ? { abortSignal: options.abortSignal } : {}),
823
+ ...(options.toolTimeoutMs !== undefined
824
+ ? { toolTimeoutMs: options.toolTimeoutMs }
825
+ : {}),
826
+ // withProviderRetry + handleProviderError are what the ai loop
827
+ // supplied around each call: without them a 429 surfaces as a raw
828
+ // upstream string instead of a RateLimitError, and a throttle is
829
+ // never retried.
830
+ runStep: (call) => withProviderRetry(call, trace.getActiveSpan() ?? undefined, `${this.providerName} generate`).catch((err) => {
831
+ throw this.handleProviderError(err);
832
+ }),
833
+ }, toolExecutionSummaries);
834
+ // Structured output rides `response_format` first. When a vendor rejects
835
+ // that outright — a tools/JSON-mode conflict, or a schema its constrained
836
+ // decoder will not accept — the recovery is to ask for the same object in
837
+ // words instead: drop `response_format` and spell the JSON Schema into the
838
+ // system prompt, letting coerceJsonToSchema recover the object from text.
839
+ //
840
+ // Ported from GenerationHandler's `promptJsonInstruction` fallback, which
841
+ // runs this on the ai-package path. That path is unreachable for every
842
+ // provider driven by this loop — GMI Cloud's MiniMax endpoint, the one it
843
+ // was written for, is a Tier-2 catalog provider on this very base class —
844
+ // so without this the recovery would simply not happen for it.
845
+ let loop;
846
+ try {
847
+ loop = await runLoop(conversation, responseFormat);
848
+ }
849
+ catch (error) {
850
+ const recoverable = responseFormat !== undefined &&
851
+ (isToolsSchemaConflictError(error) || isSchemaComplexityError(error));
852
+ if (!recoverable) {
853
+ throw error;
854
+ }
855
+ logger.warn(`[${this.providerName}] provider rejected response_format — retrying with the schema in the system prompt`, { provider: this.providerName, model: modelId });
856
+ loop = await runLoop(appendJsonSchemaInstruction(conversation, responseFormat.schema), undefined);
857
+ }
858
+ const { text, finishReason, toolsUsed } = loop;
859
+ const inputTokens = loop.inputTokens;
860
+ const outputTokens = loop.outputTokens;
861
+ const enhanced = {
862
+ content: text,
863
+ provider: this.providerName,
864
+ model: modelId,
865
+ finishReason,
866
+ usage: {
867
+ input: inputTokens,
868
+ output: outputTokens,
869
+ total: inputTokens + outputTokens,
870
+ // doGenerate reads prompt_tokens_details.cached_tokens, and the loop
871
+ // carries the counters out; discarding them here billed cached input
872
+ // at the full rate in calculateCost and made cache effectiveness
873
+ // invisible. Anthropic's native path already forwards both.
874
+ ...(loop.cacheReadTokens
875
+ ? { cacheReadTokens: loop.cacheReadTokens }
876
+ : {}),
877
+ ...(loop.cacheWriteTokens
878
+ ? { cacheCreationTokens: loop.cacheWriteTokens }
879
+ : {}),
880
+ },
881
+ responseTime: Date.now() - startTime,
882
+ toolsUsed,
883
+ toolExecutions: resolveToolExecutionRecords(options, transformToolExecutions(toolExecutionSummaries)),
884
+ enhancedWithTools: toolsUsed.length > 0,
885
+ };
886
+ return this.finalizeNativeGenerate(enhanced, options, startTime);
887
+ }
710
888
  async executeStream(options, _analysisSchema) {
711
889
  this.validateStreamOptions(options);
712
890
  const startTime = Date.now();
@@ -1,6 +1,5 @@
1
1
  import type { StreamTextResult } from "../types/index.js";
2
2
  import type { LanguageModel } from "../types/index.js";
3
- import type { streamText } from "../utils/generation.js";
4
3
  /**
5
4
  * Extract the model identifier from a LanguageModel value.
6
5
  *
@@ -20,4 +19,4 @@ export declare function getModelId(model: LanguageModel, fallback?: string): str
20
19
  * `toolResults`, `toolCalls`) exists on the SDK result with compatible types.
21
20
  * This function performs the structural down-cast without `as any`.
22
21
  */
23
- export declare function toAnalyticsStreamResult(result: ReturnType<typeof streamText>): StreamTextResult;
22
+ export declare function toAnalyticsStreamResult(result: StreamTextResult | Record<string, unknown>): StreamTextResult;
@@ -32,7 +32,11 @@ export function getModelId(model, fallback = "unknown") {
32
32
  * `toolResults`, `toolCalls`) exists on the SDK result with compatible types.
33
33
  * This function performs the structural down-cast without `as any`.
34
34
  */
35
- export function toAnalyticsStreamResult(result) {
35
+ export function toAnalyticsStreamResult(
36
+ // Was `ReturnType<typeof streamText>`. Nothing calls streamText any more —
37
+ // every streaming path is native — so the parameter is the structural
38
+ // superset this narrows FROM, stated directly.
39
+ result) {
36
40
  // The AI SDK v6 result is a structural superset of our StreamTextResult.
37
41
  // Both use PromiseLike for async fields and compatible usage shapes
38
42
  // (extractTokenUsage handles both v4 and v6 field names).