@juspay/neurolink 12.12.13 → 12.12.14

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.
@@ -1706,9 +1706,12 @@ export class BaseProvider {
1706
1706
  analytics: result.analytics,
1707
1707
  evaluation: result.evaluation,
1708
1708
  audio: result.audio,
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).
1709
+ // Forward reasoning fields. They are populated by the shared native
1710
+ // generate loop, which serves the OpenAI-compatible, Anthropic and
1711
+ // SageMaker providers (DeepSeek `reasoning_content`, gateway
1712
+ // `reasoning`, Anthropic thinking, OpenAI o-series). Vertex and AI Studio
1713
+ // override generate() and never reach that loop; they report a numeric
1714
+ // `usage.reasoning` token count and leave this text field undefined.
1712
1715
  reasoning: result.reasoning,
1713
1716
  reasoningTokens: result.reasoningTokens,
1714
1717
  };
@@ -16,8 +16,9 @@ export function toNativeToolDeclarations(tools, format) {
16
16
  const input_schema = (rawSchema
17
17
  ? convertZodToJsonSchema(rawSchema)
18
18
  : { type: "object", properties: {} });
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.
19
+ // Honor a cache breakpoint the caller set on this tool. Closing the
20
+ // stable prefix is a separate step: both Anthropic paths call
21
+ // `withLastToolCacheBreakpoint` on the assembled array afterwards.
21
22
  const cc = cacheControlOf(tool);
22
23
  const declaration = {
23
24
  name,
package/dist/neurolink.js CHANGED
@@ -4386,9 +4386,11 @@ 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
- // The native generate loop extracts these from vendor reasoning
4389
+ // The shared native generate loop extracts these from vendor reasoning
4390
4390
  // parts (DeepSeek's `reasoning_content`, Anthropic thinking blocks,
4391
- // Gemini thought parts, OpenAI o1) and they're declared on
4391
+ // OpenAI o-series) for the providers that use it — OpenAI-compatible,
4392
+ // Anthropic and SageMaker. Vertex and AI Studio override generate() and
4393
+ // leave the text field undefined. They're declared on
4392
4394
  // `GenerateResult`, but the builder previously dropped them on the
4393
4395
  // floor — so callers asking for `result.reasoning` got `undefined`
4394
4396
  // even when the model emitted a chain-of-thought.
@@ -1,9 +1,26 @@
1
1
  import type Anthropic from "@anthropic-ai/sdk";
2
2
  /**
3
- * Read an Anthropic cache breakpoint from a message/part/tool carrier.
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.
3
+ * Default the tool cache boundary to the last tool, unless the caller chose one.
4
+ *
5
+ * Tool definitions sit between the system prompt and the conversation and
6
+ * rarely change, so with no breakpoint closing that prefix the whole tools
7
+ * block is re-billed as fresh input every turn.
8
+ *
9
+ * Call it after every tool mutation — including any appended `final_result`
10
+ * tool — and before counting markers for the remaining history budget.
11
+ * Explicit caller markers are preserved, including a non-last boundary.
12
+ * Both generate and stream apply the same default.
13
+ *
14
+ * Pure — returns a new array. A tool that already carries a breakpoint wins.
15
+ */
16
+ export declare const withLastToolCacheBreakpoint: (tools: Anthropic.Messages.Tool[] | undefined) => Anthropic.Messages.Tool[] | undefined;
17
+ /**
18
+ * Read an Anthropic cache breakpoint from a message/part/tool carrier that
19
+ * still carries `providerOptions.anthropic.cacheControl` — i.e. BEFORE
20
+ * conversion to the Anthropic wire shape. MessageBuilder marks system messages
21
+ * that way. Tools are marked after conversion, by
22
+ * `withLastToolCacheBreakpoint`, which reads the wire-shaped `cache_control`
23
+ * instead; do not use this reader on an assembled tool.
7
24
  *
8
25
  * Extracted from anthropic/client.ts so `src/lib/core/nativeToolFormat.ts`
9
26
  * can share it without importing the provider client (which would create a
@@ -1,8 +1,41 @@
1
1
  /**
2
- * Read an Anthropic cache breakpoint from a message/part/tool carrier.
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.
2
+ * Default the tool cache boundary to the last tool, unless the caller chose one.
3
+ *
4
+ * Tool definitions sit between the system prompt and the conversation and
5
+ * rarely change, so with no breakpoint closing that prefix the whole tools
6
+ * block is re-billed as fresh input every turn.
7
+ *
8
+ * Call it after every tool mutation — including any appended `final_result`
9
+ * tool — and before counting markers for the remaining history budget.
10
+ * Explicit caller markers are preserved, including a non-last boundary.
11
+ * Both generate and stream apply the same default.
12
+ *
13
+ * Pure — returns a new array. A tool that already carries a breakpoint wins.
14
+ */
15
+ export const withLastToolCacheBreakpoint = (tools) => {
16
+ if (!tools || tools.length === 0) {
17
+ return tools;
18
+ }
19
+ // Read the ASSEMBLED wire field. An earlier version asked `cacheControlOf`,
20
+ // which looks at `providerOptions.anthropic.cacheControl` — a shape these
21
+ // tools no longer have by this point — so the check never fired and a
22
+ // caller-marked tool got a second, redundant marker.
23
+ if (tools.some((t) => t.cache_control !== undefined)) {
24
+ return [...tools];
25
+ }
26
+ const last = tools[tools.length - 1];
27
+ return [
28
+ ...tools.slice(0, -1),
29
+ { ...last, cache_control: { type: "ephemeral" } },
30
+ ];
31
+ };
32
+ /**
33
+ * Read an Anthropic cache breakpoint from a message/part/tool carrier that
34
+ * still carries `providerOptions.anthropic.cacheControl` — i.e. BEFORE
35
+ * conversion to the Anthropic wire shape. MessageBuilder marks system messages
36
+ * that way. Tools are marked after conversion, by
37
+ * `withLastToolCacheBreakpoint`, which reads the wire-shaped `cache_control`
38
+ * instead; do not use this reader on an assembled tool.
6
39
  *
7
40
  * Extracted from anthropic/client.ts so `src/lib/core/nativeToolFormat.ts`
8
41
  * can share it without importing the provider client (which would create a
@@ -44,7 +44,7 @@ import { createDeferredAnalytics, stringifyToolInput, } from "../openaiChatCompl
44
44
  import { createStreamChannel } from "../../core/streamChannel.js";
45
45
  import { toNativeToolDeclarations } from "../../core/nativeToolFormat.js";
46
46
  import { ANTHROPIC_BETA_HEADERS } from "./constants.js";
47
- import { cacheControlOf } from "./cacheControl.js";
47
+ import { cacheControlOf, withLastToolCacheBreakpoint } from "./cacheControl.js";
48
48
  import { appendFinalResultInstruction, appendFinalResultTool, FINAL_RESULT_TOOL_NAME, } from "./structuredOutput.js";
49
49
  // AnthropicProviderConfig is imported from types/providers.ts
50
50
  // Re-export for backward compatibility
@@ -1087,23 +1087,9 @@ 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
+ // Close the stable prefix with a breakpoint on the last tool. The
1091
+ // stream path does the same, just before its own marker count.
1092
+ tools = withLastToolCacheBreakpoint(tools);
1107
1093
  // Prompt-cache parity with the native Vertex+Claude path: upstream
1108
1094
  // layers mark the stable prefix (system via MessageBuilder, and the
1109
1095
  // last tool just above) — the growing conversation
@@ -1779,12 +1765,17 @@ export class AnthropicProvider extends BaseProvider {
1779
1765
  }
1780
1766
  }
1781
1767
  }
1768
+ // Close the stable prefix with a breakpoint on the last tool, exactly
1769
+ // as the generate path does. This was missing: the marker was applied
1770
+ // only in doGenerate, so a streaming turn re-billed the entire tools
1771
+ // block every step and could not reuse the prefix generate() cached.
1772
+ const cachedTools = withLastToolCacheBreakpoint(anthropicTools);
1782
1773
  // Prompt-cache parity with the native Vertex+Claude path — rolling
1783
1774
  // history breakpoints, re-applied per step so the stable prefix stays
1784
1775
  // byte-identical while the breakpoint follows the growing tail.
1785
1776
  const cacheMarkersUsed = countAnthropicCacheMarkers({
1786
1777
  system: payload.system,
1787
- tools: anthropicTools,
1778
+ tools: cachedTools,
1788
1779
  messages: conversation,
1789
1780
  });
1790
1781
  const cachedConversation = applyAnthropicHistoryCacheBreakpoints(conversation, ANTHROPIC_MAX_CACHE_BREAKPOINTS - cacheMarkersUsed);
@@ -1803,8 +1794,8 @@ export class AnthropicProvider extends BaseProvider {
1803
1794
  ...(streamSamplingParams.temperature !== undefined
1804
1795
  ? { temperature: streamSamplingParams.temperature }
1805
1796
  : {}),
1806
- ...(anthropicTools && anthropicTools.length > 0
1807
- ? { tools: anthropicTools }
1797
+ ...(cachedTools && cachedTools.length > 0
1798
+ ? { tools: cachedTools }
1808
1799
  : {}),
1809
1800
  ...(anthropicToolChoice ? { tool_choice: anthropicToolChoice } : {}),
1810
1801
  ...(thinking ? { thinking } : {}),
@@ -3,18 +3,6 @@
3
3
  * Service registry, dependency injection, and service management types
4
4
  */
5
5
  import type { UnknownRecord } from "./common.js";
6
- /**
7
- * Service factory function type
8
- */
9
- export type ServiceFactory<T = unknown> = () => T | Promise<T>;
10
- /**
11
- * Service registration configuration
12
- */
13
- export type ServiceRegistration<T = unknown> = {
14
- factory: ServiceFactory<T>;
15
- singleton: boolean;
16
- instance?: T;
17
- };
18
6
  /**
19
7
  * Service definition with metadata and status
20
8
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "12.12.13",
3
+ "version": "12.12.14",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (connect any MCP server), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
6
6
  "author": {