@juspay/neurolink 12.12.13 → 12.12.15
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 +2 -2
- package/dist/browser/neurolink.min.js +351 -351
- package/dist/core/baseProvider.js +6 -3
- package/dist/core/nativeToolFormat.js +3 -2
- package/dist/neurolink.js +4 -2
- package/dist/providers/amazonSagemaker.js +61 -1
- package/dist/providers/anthropic/cacheControl.d.ts +21 -4
- package/dist/providers/anthropic/cacheControl.js +37 -4
- package/dist/providers/anthropic/client.js +12 -21
- package/dist/providers/sagemaker/language-model.js +8 -3
- package/dist/types/service.d.ts +0 -12
- package/package.json +1 -1
|
@@ -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
|
|
1710
|
-
//
|
|
1711
|
-
//
|
|
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.
|
|
20
|
-
//
|
|
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
|
-
//
|
|
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.
|
|
@@ -139,7 +139,67 @@ export class AmazonSageMakerProvider extends BaseProvider {
|
|
|
139
139
|
if (!hasNativeDoGenerate(model)) {
|
|
140
140
|
throw this.handleProviderError(new Error("sagemaker: model handle exposes no doGenerate()"));
|
|
141
141
|
}
|
|
142
|
-
const doGenerate =
|
|
142
|
+
const doGenerate = async (call) => {
|
|
143
|
+
const format = call.responseFormat;
|
|
144
|
+
const result = await model.doGenerate({
|
|
145
|
+
...call,
|
|
146
|
+
...(call.maxOutputTokens !== undefined
|
|
147
|
+
? { maxTokens: call.maxOutputTokens }
|
|
148
|
+
: {}),
|
|
149
|
+
...(format?.type === "json"
|
|
150
|
+
? {
|
|
151
|
+
responseFormat: format.schema
|
|
152
|
+
? {
|
|
153
|
+
type: "json_schema",
|
|
154
|
+
json_schema: { name: "response", schema: format.schema },
|
|
155
|
+
}
|
|
156
|
+
: { type: "json_object" },
|
|
157
|
+
}
|
|
158
|
+
: {}),
|
|
159
|
+
});
|
|
160
|
+
// SageMaker's low-level model retains its legacy result for streaming
|
|
161
|
+
// and direct consumers. The shared loop consumes V3 content and usage.
|
|
162
|
+
if (Array.isArray(result.content)) {
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
const content = [];
|
|
166
|
+
if (typeof result.text === "string" && result.text) {
|
|
167
|
+
content.push({ type: "text", text: result.text });
|
|
168
|
+
}
|
|
169
|
+
if (typeof result.reasoning === "string" && result.reasoning) {
|
|
170
|
+
content.push({ type: "reasoning", text: result.reasoning });
|
|
171
|
+
}
|
|
172
|
+
for (const call of Array.isArray(result.toolCalls)
|
|
173
|
+
? result.toolCalls
|
|
174
|
+
: []) {
|
|
175
|
+
if (typeof call !== "object" || call === null) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const item = call;
|
|
179
|
+
const fn = item.function;
|
|
180
|
+
if (typeof item.id === "string" && typeof fn?.name === "string") {
|
|
181
|
+
content.push({
|
|
182
|
+
type: "tool-call",
|
|
183
|
+
toolCallId: item.id,
|
|
184
|
+
toolName: fn.name,
|
|
185
|
+
input: fn.arguments ?? "{}",
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const usage = result.usage;
|
|
190
|
+
return {
|
|
191
|
+
...result,
|
|
192
|
+
content,
|
|
193
|
+
usage: {
|
|
194
|
+
inputTokens: {
|
|
195
|
+
total: typeof usage?.inputTokens === "number" ? usage.inputTokens : 0,
|
|
196
|
+
},
|
|
197
|
+
outputTokens: {
|
|
198
|
+
total: typeof usage?.outputTokens === "number" ? usage.outputTokens : 0,
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
};
|
|
143
203
|
const shouldUseTools = !options.disableTools && this.supportsTools();
|
|
144
204
|
const toolsRecord = shouldUseTools
|
|
145
205
|
? options.tools || {}
|
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
import type Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
|
1091
|
-
//
|
|
1092
|
-
|
|
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:
|
|
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
|
-
...(
|
|
1807
|
-
? { tools:
|
|
1797
|
+
...(cachedTools && cachedTools.length > 0
|
|
1798
|
+
? { tools: cachedTools }
|
|
1808
1799
|
: {}),
|
|
1809
1800
|
...(anthropicToolChoice ? { tool_choice: anthropicToolChoice } : {}),
|
|
1810
1801
|
...(thinking ? { thinking } : {}),
|
|
@@ -399,8 +399,8 @@ export class SageMakerLanguageModel {
|
|
|
399
399
|
...(options.maxTokens !== undefined
|
|
400
400
|
? { max_new_tokens: options.maxTokens }
|
|
401
401
|
: {}),
|
|
402
|
-
temperature: options.temperature
|
|
403
|
-
top_p: options.topP
|
|
402
|
+
temperature: options.temperature ?? 0.7,
|
|
403
|
+
top_p: options.topP ?? 0.9,
|
|
404
404
|
stop: options.stopSequences || [],
|
|
405
405
|
},
|
|
406
406
|
};
|
|
@@ -582,9 +582,14 @@ export class SageMakerLanguageModel {
|
|
|
582
582
|
// Handle response with tool calls
|
|
583
583
|
if (responseBody.choices && Array.isArray(responseBody.choices)) {
|
|
584
584
|
const choice = responseBody.choices[0];
|
|
585
|
-
if (choice?.message?.content) {
|
|
585
|
+
if (typeof choice?.message?.content === "string") {
|
|
586
586
|
return choice.message.content;
|
|
587
587
|
}
|
|
588
|
+
// A tool-only assistant turn has no text. Serializing the entire
|
|
589
|
+
// endpoint response here would replay its envelope as assistant prose.
|
|
590
|
+
if (choice?.message?.tool_calls?.length) {
|
|
591
|
+
return "";
|
|
592
|
+
}
|
|
588
593
|
}
|
|
589
594
|
// Fallback: stringify the entire response
|
|
590
595
|
return JSON.stringify(responseBody);
|
package/dist/types/service.d.ts
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "12.12.15",
|
|
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": {
|