@juspay/neurolink 9.67.2 → 9.68.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.
@@ -318,6 +318,45 @@ export const mapNeuroLinkToolChoice = (choice) => {
318
318
  }
319
319
  return undefined;
320
320
  };
321
+ // OpenAI-compatible endpoints (OpenAI, DeepSeek, …) reject
322
+ // `response_format: { type: "json_object" }` unless the literal word "json"
323
+ // appears somewhere in the messages. The `@ai-sdk/openai-compatible` wrapper
324
+ // this client replaced injected that instruction for us; the native client
325
+ // must do the same or json_object requests 400.
326
+ export const messagesContainJsonWord = (messages) => messages.some((m) => {
327
+ const c = m.content;
328
+ if (typeof c === "string") {
329
+ return /\bjson\b/i.test(c);
330
+ }
331
+ if (Array.isArray(c)) {
332
+ return c.some((part) => typeof part?.text === "string" &&
333
+ /\bjson\b/i.test(part.text));
334
+ }
335
+ return false;
336
+ });
337
+ // Prepends a minimal JSON-instruction system message to the FINAL wire body
338
+ // when json_object mode is requested and its messages don't already mention
339
+ // "json". Operates on the post-`adjustRequestBody` body so the guard reflects
340
+ // whatever a subclass left on the wire (response_format/messages it may have
341
+ // rewritten), not an intermediate state. No-op otherwise.
342
+ export const ensureJsonWordInBody = (body) => body.response_format?.type === "json_object" &&
343
+ !messagesContainJsonWord(body.messages)
344
+ ? {
345
+ ...body,
346
+ messages: [
347
+ {
348
+ role: "system",
349
+ content: "Respond with valid JSON only — no prose, no markdown fencing.",
350
+ },
351
+ ...body.messages,
352
+ ],
353
+ }
354
+ : body;
355
+ // Reasoning-class OpenAI models (o-series, gpt-5+) reject `max_tokens` and
356
+ // require `max_completion_tokens`. The OpenAI + Azure providers use this to
357
+ // rename the field on the wire body; third-party OpenAI-compatible endpoints
358
+ // keep `max_tokens`, so it is opt-in per provider, never applied by default.
359
+ export const requiresMaxCompletionTokens = (modelId) => /^(o\d|gpt-5)/i.test(modelId.replace(/^.*\//, ""));
321
360
  export const buildBody = (args) => {
322
361
  const { modelId, messages, options, tools, toolChoice, streaming, responseFormat, } = args;
323
362
  const body = {
@@ -1,77 +1,21 @@
1
1
  import type { AIProviderName } from "../constants/enums.js";
2
- import { BaseProvider } from "../core/baseProvider.js";
3
- import type { LanguageModel, Schema, StreamOptions, StreamResult, ZodUnknownSchema } from "../types/index.js";
2
+ import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
4
3
  /**
5
4
  * OpenAI Compatible Provider — direct HTTP, no AI SDK.
6
5
  *
7
6
  * Talks to any OpenAI chat-completions-shaped endpoint (LiteLLM, vLLM,
8
- * OpenRouter, etc.). The entire request/stream/tool-loop is inline above;
9
- * no `streamText`, no `LanguageModelV3`, no `@ai-sdk/openai`.
7
+ * OpenRouter, etc.). All request/stream/tool-loop orchestration lives in
8
+ * `OpenAIChatCompletionsProvider`. This class just declares config and
9
+ * provider-specific error mapping.
10
10
  */
11
- export declare class OpenAICompatibleProvider extends BaseProvider {
12
- private config;
13
- private resolvedModel?;
14
- private discoveredModel?;
11
+ export declare class OpenAICompatibleProvider extends OpenAIChatCompletionsProvider {
15
12
  constructor(modelName?: string, sdk?: unknown, _region?: string, credentials?: {
16
13
  apiKey?: string;
17
14
  baseURL?: string;
18
15
  });
19
16
  protected getProviderName(): AIProviderName;
20
17
  protected getDefaultModel(): string;
21
- /**
22
- * Abstract from BaseProvider — used by the parent's generate() path which
23
- * still goes through `generateText`. Returns a thin LanguageModelV3-shaped
24
- * object that delegates to the same HTTP helpers used by executeStream.
25
- * Stays inside this file so no AI-SDK-named import is needed here.
26
- */
27
- protected getAISDKModel(): Promise<LanguageModel>;
28
- private resolveModelName;
29
- /**
30
- * Returns a minimal V3-shaped model. Only used by BaseProvider's
31
- * `generate()` non-streaming path which still relies on the parent's
32
- * `generateText`. The streaming path bypasses this entirely.
33
- */
34
- private buildDelegatingModel;
18
+ protected getFallbackModelName(): string;
19
+ protected getFallbackModels(): string[];
35
20
  protected formatProviderError(error: unknown): Error;
36
- supportsTools(): boolean;
37
- /**
38
- * Streaming path — drives the OpenAI endpoint directly. No streamText,
39
- * no AI SDK orchestrator. Tool calls, multi-step loops, telemetry,
40
- * abort handling all inline.
41
- */
42
- protected executeStream(options: StreamOptions, _analysisSchema?: ZodUnknownSchema | Schema<unknown>): Promise<StreamResult>;
43
- /**
44
- * Multi-step streaming orchestrator. One iteration per model turn:
45
- *
46
- * 1. POST /chat/completions with stream:true
47
- * 2. Parse SSE; push text deltas to the consumer queue
48
- * 3. If the step emitted tool_calls → execute each, append to
49
- * conversation, loop again
50
- * 4. Otherwise resolve the deferred analytics promises and exit
51
- *
52
- * Bounded by `args.maxSteps`. Any thrown error rejects loopPromise and
53
- * is surfaced to the consumer via `await loopPromise` in the stream
54
- * generator.
55
- */
56
- private runStreamLoop;
57
- /**
58
- * One streaming round-trip: POST chat-completions, parse SSE, push text
59
- * deltas to the consumer queue. Returns the accumulated SSE result so
60
- * the caller can decide whether to run tools and re-stream.
61
- */
62
- private streamOneStep;
63
- /**
64
- * Execute every tool_call collected from one streaming step:
65
- *
66
- * - append an `assistant` turn carrying the tool_calls
67
- * - resolve each tool from the local registry and run it
68
- * - emit tool:start/tool:end events
69
- * - push per-execution summaries
70
- * - append a `tool` turn per result so the next step can see them
71
- * - mirror BaseProvider's tool-events + storage hooks
72
- */
73
- private executeToolBatch;
74
- getAvailableModels(): Promise<string[]>;
75
- getFirstAvailableModel(): Promise<string>;
76
- private getFallbackModels;
77
21
  }