@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.
- package/CHANGELOG.md +3 -4
- package/dist/browser/neurolink.min.js +533 -581
- package/dist/constants/enums.d.ts +13 -0
- package/dist/constants/enums.js +14 -0
- package/dist/core/baseProvider.d.ts +71 -3
- package/dist/core/baseProvider.js +152 -44
- package/dist/core/modules/GenerationHandler.d.ts +22 -24
- package/dist/core/modules/GenerationHandler.js +28 -463
- package/dist/core/nativeGenerateLoop.d.ts +35 -0
- package/dist/core/nativeGenerateLoop.js +261 -0
- package/dist/files/fileTools.d.ts +5 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -0
- package/dist/middleware/builtin/guardrails.d.ts +0 -5
- package/dist/middleware/builtin/guardrails.js +33 -5
- package/dist/middleware/factory.js +1 -1
- package/dist/middleware/wrapLanguageModel.d.ts +18 -0
- package/dist/middleware/wrapLanguageModel.js +53 -0
- package/dist/processors/media/AudioProcessor.js +46 -11
- package/dist/providers/amazonSagemaker.d.ts +17 -1
- package/dist/providers/amazonSagemaker.js +110 -0
- package/dist/providers/anthropic/client.d.ts +11 -0
- package/dist/providers/anthropic/client.js +148 -1
- package/dist/providers/catalog/index.generated.d.ts +1 -1
- package/dist/providers/catalog/index.generated.js +3 -0
- package/dist/providers/catalog/loader.js +1 -0
- package/dist/providers/catalog/mancer.json +192 -0
- package/dist/providers/configuredOpenAICompat.d.ts +11 -0
- package/dist/providers/configuredOpenAICompat.js +16 -0
- package/dist/providers/googleVertex/client.d.ts +0 -9
- package/dist/providers/googleVertex/client.js +0 -33
- package/dist/providers/openaiChatCompletionsBase.d.ts +21 -1
- package/dist/providers/openaiChatCompletionsBase.js +178 -0
- package/dist/providers/providerTypeUtils.d.ts +1 -2
- package/dist/providers/providerTypeUtils.js +5 -1
- package/dist/types/aiCompat.d.ts +485 -0
- package/dist/types/aiCompat.js +17 -0
- package/dist/types/conversation.d.ts +1 -1
- package/dist/types/generate.d.ts +52 -0
- package/dist/types/middleware.d.ts +3 -6
- package/dist/types/providerCatalog.generated.d.ts +2 -2
- package/dist/types/providers.d.ts +14 -1
- package/dist/types/tools.d.ts +2 -2
- package/dist/utils/generationErrors.d.ts +78 -6
- package/dist/utils/generationErrors.js +114 -6
- package/dist/utils/nativeSingleShot.d.ts +3 -0
- package/dist/utils/nativeSingleShot.js +83 -0
- package/dist/utils/tool.d.ts +30 -5
- package/dist/utils/tool.js +43 -5
- package/package.json +3 -6
- package/dist/utils/generation.d.ts +0 -8
- 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:
|
|
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(
|
|
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).
|