@juspay/neurolink 12.19.0 → 12.19.1

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.
@@ -22,6 +22,24 @@ export declare class CodexFallbackStreamError extends Error {
22
22
  readonly usage?: CodexFallbackResult["usage"];
23
23
  constructor(payload: Record<string, unknown>, eventType: string, usage?: CodexFallbackResult["usage"]);
24
24
  }
25
+ /**
26
+ * Stable per-conversation routing key for OpenAI prompt caching.
27
+ *
28
+ * Anthropic caching is explicit — the client marks breakpoints and the provider
29
+ * honours them. OpenAI caching is automatic: a prefix is reused only when the
30
+ * request lands on infrastructure already holding it, and `prompt_cache_key` is
31
+ * what pins a conversation to one. Without it this hop takes its chances on
32
+ * routing, which is the worst case for a fallback that arrives in bursts
33
+ * separated by long gaps.
34
+ *
35
+ * Claude Code carries its session id inside `metadata.user_id`, alongside
36
+ * account and device identifiers. Only the session id is read, and it is
37
+ * hashed, so no account or device identifier reaches the upstream. When no
38
+ * session id can be recovered the field is omitted rather than filled with
39
+ * something shared: a key common to every conversation would pin unrelated
40
+ * prefixes onto one cache instead of separating them.
41
+ */
42
+ export declare function codexPromptCacheKey(body: ClaudeRequest): string | undefined;
25
43
  /** Convert a Claude Messages request into the ChatGPT Codex Responses shape. */
26
44
  export declare function convertClaudeRequestToCodex(body: ClaudeRequest, model: string, reasoningEffort?: CodexReasoningEffort): CodexResponsesRequest;
27
45
  /**
@@ -6,6 +6,7 @@
6
6
  * in the native Codex proxy handler so fallback traffic follows the same pool
7
7
  * rules as a native Codex request.
8
8
  */
9
+ import { createHash } from "node:crypto";
9
10
  import { ClaudeStreamSerializer, generateToolUseId } from "./claudeFormat.js";
10
11
  import { classifyProxyFailureCode } from "./proxyFailureDetails.js";
11
12
  import { extractCodexUsage } from "./codexUsage.js";
@@ -235,6 +236,45 @@ function convertClaudeMessage(role, content) {
235
236
  flushMessage();
236
237
  return input;
237
238
  }
239
+ /**
240
+ * Stable per-conversation routing key for OpenAI prompt caching.
241
+ *
242
+ * Anthropic caching is explicit — the client marks breakpoints and the provider
243
+ * honours them. OpenAI caching is automatic: a prefix is reused only when the
244
+ * request lands on infrastructure already holding it, and `prompt_cache_key` is
245
+ * what pins a conversation to one. Without it this hop takes its chances on
246
+ * routing, which is the worst case for a fallback that arrives in bursts
247
+ * separated by long gaps.
248
+ *
249
+ * Claude Code carries its session id inside `metadata.user_id`, alongside
250
+ * account and device identifiers. Only the session id is read, and it is
251
+ * hashed, so no account or device identifier reaches the upstream. When no
252
+ * session id can be recovered the field is omitted rather than filled with
253
+ * something shared: a key common to every conversation would pin unrelated
254
+ * prefixes onto one cache instead of separating them.
255
+ */
256
+ export function codexPromptCacheKey(body) {
257
+ const raw = body.metadata?.user_id;
258
+ if (typeof raw !== "string" || raw.length === 0) {
259
+ return undefined;
260
+ }
261
+ let parsed;
262
+ try {
263
+ parsed = JSON.parse(raw);
264
+ }
265
+ catch {
266
+ return undefined;
267
+ }
268
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
269
+ return undefined;
270
+ }
271
+ const fields = parsed;
272
+ const sessionId = fields.session_id ?? fields.parent_session_id;
273
+ if (typeof sessionId !== "string" || sessionId.length === 0) {
274
+ return undefined;
275
+ }
276
+ return createHash("sha256").update(sessionId).digest("hex");
277
+ }
238
278
  /** Convert a Claude Messages request into the ChatGPT Codex Responses shape. */
239
279
  export function convertClaudeRequestToCodex(body, model, reasoningEffort) {
240
280
  const input = body.messages.flatMap((message) => message.role === "system"
@@ -250,6 +290,10 @@ export function convertClaudeRequestToCodex(body, model, reasoningEffort) {
250
290
  ? { reasoning: { effort: reasoningEffort } }
251
291
  : {}),
252
292
  };
293
+ const promptCacheKey = codexPromptCacheKey(body);
294
+ if (promptCacheKey) {
295
+ request.prompt_cache_key = promptCacheKey;
296
+ }
253
297
  const instructions = buildSystemInstructions(body);
254
298
  if (instructions) {
255
299
  request.instructions = instructions;
@@ -156,6 +156,8 @@ export type CodexResponsesRequest = {
156
156
  input: CodexResponsesInputItem[];
157
157
  stream: true;
158
158
  store: false;
159
+ /** Pins one conversation to the cache that already holds its prefix. */
160
+ prompt_cache_key?: string;
159
161
  reasoning?: {
160
162
  effort: CodexReasoningEffort;
161
163
  };