@juspay/neurolink 12.20.0 → 12.20.2
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 -6
- package/dist/browser/neurolink.min.js +400 -400
- package/dist/cli/commands/proxy.js +171 -25
- package/dist/cli/commands/telemetry.d.ts +4 -1
- package/dist/cli/commands/telemetry.js +113 -0
- package/dist/cli/utils/nativeTelemetry.d.ts +19 -0
- package/dist/cli/utils/nativeTelemetry.js +322 -0
- package/dist/proxy/bodyCapturePolicy.d.ts +6 -0
- package/dist/proxy/bodyCapturePolicy.js +132 -0
- package/dist/proxy/codexFallback.d.ts +27 -9
- package/dist/proxy/codexFallback.js +84 -13
- package/dist/proxy/openaiFormat.js +8 -1
- package/dist/proxy/otelLogSink.d.ts +11 -1
- package/dist/proxy/otelLogSink.js +174 -27
- package/dist/proxy/otlpLogTransport.d.ts +4 -2
- package/dist/proxy/otlpLogTransport.js +22 -7
- package/dist/proxy/requestLogger.js +11 -3
- package/dist/proxy/restartControl.js +18 -3
- package/dist/proxy/rollingProxyServer.js +48 -1
- package/dist/proxy/rollingWorkerProcess.js +87 -10
- package/dist/proxy/rollingWorkerProtocol.js +4 -2
- package/dist/proxy/rollingWorkerSupervisor.js +47 -10
- package/dist/proxy/socketWorkerRuntime.js +90 -4
- package/dist/proxy/updateChecker.d.ts +3 -3
- package/dist/proxy/updateChecker.js +16 -9
- package/dist/proxy/updateCoordinator.d.ts +10 -1
- package/dist/proxy/updateCoordinator.js +68 -1
- package/dist/proxy/updateState.d.ts +2 -0
- package/dist/proxy/updateState.js +15 -0
- package/dist/proxy/vertexAnthropicFallback.d.ts +17 -1
- package/dist/proxy/vertexAnthropicFallback.js +25 -1
- package/dist/server/routes/claudeProxyRoutes.d.ts +17 -0
- package/dist/server/routes/claudeProxyRoutes.js +53 -5
- package/dist/types/cli.d.ts +18 -0
- package/dist/types/providers.d.ts +8 -0
- package/dist/types/proxy.d.ts +117 -7
- package/dist/utils/anthropicCacheBreakpoints.d.ts +22 -1
- package/dist/utils/anthropicCacheBreakpoints.js +113 -0
- package/dist/utils/pricing.js +69 -2
- package/docs-site/static/search-index.json +1 -1
- package/package.json +1 -1
- package/scripts/observability/NATIVE-DURABLE.md +68 -0
- package/scripts/observability/otel-collector.proxy-native-durable.yaml +2 -2
- package/scripts/observability/proxy-telemetry-check.mjs +135 -50
|
@@ -148,3 +148,116 @@ function markLastContentBlock(messages, i) {
|
|
|
148
148
|
messages[i] = { ...message, content };
|
|
149
149
|
return true;
|
|
150
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Breakpoint placement for a Claude Messages request the proxy built itself,
|
|
153
|
+
* rather than one a client authored.
|
|
154
|
+
*
|
|
155
|
+
* A request translated from another wire format arrives with no markers at
|
|
156
|
+
* all, because the format it came from has no way to express one: OpenAI-shaped
|
|
157
|
+
* callers rely on automatic prefix caching, which Anthropic does not do. A
|
|
158
|
+
* faithful translation is therefore cached at 0% on every turn, and a caller
|
|
159
|
+
* that fell back here from an exhausted pool burns the replacement quota faster
|
|
160
|
+
* than the one it was spared.
|
|
161
|
+
*
|
|
162
|
+
* Placement follows Anthropic's `tools → system → messages` rendering: one
|
|
163
|
+
* marker on the last system block covers tools *and* system in a single
|
|
164
|
+
* breakpoint, and the rest roll along the tail of the history so a growing
|
|
165
|
+
* conversation keeps its settled prefix cached. Markers the caller supplied are
|
|
166
|
+
* counted first and never displaced — this only spends what is left of the
|
|
167
|
+
* four.
|
|
168
|
+
*
|
|
169
|
+
* Pure: inputs are cloned, never mutated.
|
|
170
|
+
*/
|
|
171
|
+
export function applyClaudeRequestCacheBreakpoints(request) {
|
|
172
|
+
const existing = countAnthropicCacheMarkers({
|
|
173
|
+
system: request.system,
|
|
174
|
+
tools: request.tools,
|
|
175
|
+
messages: [],
|
|
176
|
+
});
|
|
177
|
+
const inMessages = request.messages.reduce((n, m) => n +
|
|
178
|
+
(Array.isArray(m.content)
|
|
179
|
+
? m.content.filter((b) => "cache_control" in b && b.cache_control)
|
|
180
|
+
.length
|
|
181
|
+
: 0), 0);
|
|
182
|
+
let budget = MAX_BREAKPOINTS - existing - inMessages;
|
|
183
|
+
if (budget <= 0) {
|
|
184
|
+
return request;
|
|
185
|
+
}
|
|
186
|
+
const out = { ...request };
|
|
187
|
+
// One marker on the stable head. The last system block is the better anchor
|
|
188
|
+
// than the last tool, because system renders after tools and so a single
|
|
189
|
+
// marker there caches both.
|
|
190
|
+
if (Array.isArray(out.system) && out.system.length > 0 && existing === 0) {
|
|
191
|
+
const system = out.system.map((b) => ({ ...b }));
|
|
192
|
+
system[system.length - 1] = {
|
|
193
|
+
...system[system.length - 1],
|
|
194
|
+
cache_control: CLAUDE_EPHEMERAL,
|
|
195
|
+
};
|
|
196
|
+
out.system = system;
|
|
197
|
+
budget--;
|
|
198
|
+
}
|
|
199
|
+
else if ((!out.system || (Array.isArray(out.system) && out.system.length === 0)) &&
|
|
200
|
+
out.tools &&
|
|
201
|
+
out.tools.length > 0 &&
|
|
202
|
+
existing === 0) {
|
|
203
|
+
const tools = out.tools.map((t) => ({ ...t }));
|
|
204
|
+
tools[tools.length - 1] = {
|
|
205
|
+
...tools[tools.length - 1],
|
|
206
|
+
cache_control: CLAUDE_EPHEMERAL,
|
|
207
|
+
};
|
|
208
|
+
out.tools = tools;
|
|
209
|
+
budget--;
|
|
210
|
+
}
|
|
211
|
+
if (budget > 0) {
|
|
212
|
+
out.messages = applyClaudeHistoryBreakpoints(out.messages, budget);
|
|
213
|
+
}
|
|
214
|
+
return out;
|
|
215
|
+
}
|
|
216
|
+
const CLAUDE_EPHEMERAL = { type: "ephemeral" };
|
|
217
|
+
/**
|
|
218
|
+
* Roll `budget` markers backwards along the history, marking the last content
|
|
219
|
+
* block of each message that can carry one. Only text and tool_result blocks
|
|
220
|
+
* accept `cache_control`; a message ending in anything else is skipped without
|
|
221
|
+
* spending budget.
|
|
222
|
+
*
|
|
223
|
+
* A message whose content is a plain string is promoted to the single text
|
|
224
|
+
* block the marker has to live on. Skipping strings instead would have left an
|
|
225
|
+
* ordinary conversation with no history breakpoint at all, since the OpenAI
|
|
226
|
+
* bridge emits every plain-text turn as a string — which is precisely the
|
|
227
|
+
* growing history this is here to keep cached.
|
|
228
|
+
*/
|
|
229
|
+
function applyClaudeHistoryBreakpoints(input, budget) {
|
|
230
|
+
const messages = input.map((m) => ({ ...m }));
|
|
231
|
+
let remaining = Math.max(0, Math.min(budget, MAX_BREAKPOINTS));
|
|
232
|
+
for (let i = messages.length - 1; i >= 0 && remaining > 0; i--) {
|
|
233
|
+
const content = messages[i].content;
|
|
234
|
+
if (typeof content === "string") {
|
|
235
|
+
if (content.length === 0) {
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
messages[i] = {
|
|
239
|
+
...messages[i],
|
|
240
|
+
content: [
|
|
241
|
+
{ type: "text", text: content, cache_control: CLAUDE_EPHEMERAL },
|
|
242
|
+
],
|
|
243
|
+
};
|
|
244
|
+
remaining--;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (!Array.isArray(content) || content.length === 0) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const last = content[content.length - 1];
|
|
251
|
+
if (last.type !== "text" && last.type !== "tool_result") {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (last.cache_control) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const blocks = content.map((b) => ({ ...b }));
|
|
258
|
+
blocks[blocks.length - 1] = { ...last, cache_control: CLAUDE_EPHEMERAL };
|
|
259
|
+
messages[i] = { ...messages[i], content: blocks };
|
|
260
|
+
remaining--;
|
|
261
|
+
}
|
|
262
|
+
return messages;
|
|
263
|
+
}
|
package/dist/utils/pricing.js
CHANGED
|
@@ -78,8 +78,28 @@ const PRICING = {
|
|
|
78
78
|
// Anthropic (direct API) — updated March 2026
|
|
79
79
|
anthropic: {
|
|
80
80
|
// Claude 5 family. Rates from platform.claude.com/docs/en/about-claude/pricing
|
|
81
|
-
// (checked 2026-
|
|
82
|
-
//
|
|
81
|
+
// (checked 2026-09-23). A 5-minute cache write is 1.25x base input. The cache
|
|
82
|
+
// hit multiplier is 0.1x for most models but 0.05x on Opus 5.5 and 0.025x on
|
|
83
|
+
// Fable/Mythos 5.1, so those three are listed in full rather than left to the
|
|
84
|
+
// longest-prefix fallback — which would silently quote the 5.0 family's rates.
|
|
85
|
+
"claude-fable-5-1": {
|
|
86
|
+
input: 10.0 / 1_000_000,
|
|
87
|
+
output: 50.0 / 1_000_000,
|
|
88
|
+
cacheRead: 0.25 / 1_000_000,
|
|
89
|
+
cacheCreation: 12.5 / 1_000_000,
|
|
90
|
+
},
|
|
91
|
+
"claude-mythos-5-1": {
|
|
92
|
+
input: 10.0 / 1_000_000,
|
|
93
|
+
output: 50.0 / 1_000_000,
|
|
94
|
+
cacheRead: 0.25 / 1_000_000,
|
|
95
|
+
cacheCreation: 12.5 / 1_000_000,
|
|
96
|
+
},
|
|
97
|
+
"claude-opus-5-5": {
|
|
98
|
+
input: 4.0 / 1_000_000,
|
|
99
|
+
output: 20.0 / 1_000_000,
|
|
100
|
+
cacheRead: 0.2 / 1_000_000,
|
|
101
|
+
cacheCreation: 5.0 / 1_000_000,
|
|
102
|
+
},
|
|
83
103
|
"claude-fable-5": {
|
|
84
104
|
input: 10.0 / 1_000_000,
|
|
85
105
|
output: 50.0 / 1_000_000,
|
|
@@ -226,6 +246,53 @@ const PRICING = {
|
|
|
226
246
|
},
|
|
227
247
|
// Google Vertex AI — Claude models on Vertex (same pricing, @ date suffix)
|
|
228
248
|
vertex: {
|
|
249
|
+
// Claude 5 family. Absent here until now, so a Vertex leg serving any of
|
|
250
|
+
// them resolved to no rate at all and booked the turn at $0 — on the one
|
|
251
|
+
// provider in the chain that bills in real currency.
|
|
252
|
+
// `isVertexAnthropicModel` admits every `claude-*` id, so the whole
|
|
253
|
+
// family needs an entry, not only the ones the chain names today.
|
|
254
|
+
"claude-fable-5-1": {
|
|
255
|
+
input: 10.0 / 1_000_000,
|
|
256
|
+
output: 50.0 / 1_000_000,
|
|
257
|
+
cacheRead: 0.25 / 1_000_000,
|
|
258
|
+
cacheCreation: 12.5 / 1_000_000,
|
|
259
|
+
},
|
|
260
|
+
"claude-mythos-5-1": {
|
|
261
|
+
input: 10.0 / 1_000_000,
|
|
262
|
+
output: 50.0 / 1_000_000,
|
|
263
|
+
cacheRead: 0.25 / 1_000_000,
|
|
264
|
+
cacheCreation: 12.5 / 1_000_000,
|
|
265
|
+
},
|
|
266
|
+
"claude-fable-5": {
|
|
267
|
+
input: 10.0 / 1_000_000,
|
|
268
|
+
output: 50.0 / 1_000_000,
|
|
269
|
+
cacheRead: 1.0 / 1_000_000,
|
|
270
|
+
cacheCreation: 12.5 / 1_000_000,
|
|
271
|
+
},
|
|
272
|
+
"claude-mythos-5": {
|
|
273
|
+
input: 10.0 / 1_000_000,
|
|
274
|
+
output: 50.0 / 1_000_000,
|
|
275
|
+
cacheRead: 1.0 / 1_000_000,
|
|
276
|
+
cacheCreation: 12.5 / 1_000_000,
|
|
277
|
+
},
|
|
278
|
+
"claude-opus-5-5": {
|
|
279
|
+
input: 4.0 / 1_000_000,
|
|
280
|
+
output: 20.0 / 1_000_000,
|
|
281
|
+
cacheRead: 0.2 / 1_000_000,
|
|
282
|
+
cacheCreation: 5.0 / 1_000_000,
|
|
283
|
+
},
|
|
284
|
+
"claude-opus-5": {
|
|
285
|
+
input: 5.0 / 1_000_000,
|
|
286
|
+
output: 25.0 / 1_000_000,
|
|
287
|
+
cacheRead: 0.5 / 1_000_000,
|
|
288
|
+
cacheCreation: 6.25 / 1_000_000,
|
|
289
|
+
},
|
|
290
|
+
"claude-sonnet-5": {
|
|
291
|
+
input: 2.0 / 1_000_000,
|
|
292
|
+
output: 10.0 / 1_000_000,
|
|
293
|
+
cacheRead: 0.2 / 1_000_000,
|
|
294
|
+
cacheCreation: 2.5 / 1_000_000,
|
|
295
|
+
},
|
|
229
296
|
"claude-sonnet-4-6": {
|
|
230
297
|
input: 3.0 / 1_000_000,
|
|
231
298
|
output: 15.0 / 1_000_000,
|