@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.
Files changed (44) hide show
  1. package/CHANGELOG.md +2 -6
  2. package/dist/browser/neurolink.min.js +400 -400
  3. package/dist/cli/commands/proxy.js +171 -25
  4. package/dist/cli/commands/telemetry.d.ts +4 -1
  5. package/dist/cli/commands/telemetry.js +113 -0
  6. package/dist/cli/utils/nativeTelemetry.d.ts +19 -0
  7. package/dist/cli/utils/nativeTelemetry.js +322 -0
  8. package/dist/proxy/bodyCapturePolicy.d.ts +6 -0
  9. package/dist/proxy/bodyCapturePolicy.js +132 -0
  10. package/dist/proxy/codexFallback.d.ts +27 -9
  11. package/dist/proxy/codexFallback.js +84 -13
  12. package/dist/proxy/openaiFormat.js +8 -1
  13. package/dist/proxy/otelLogSink.d.ts +11 -1
  14. package/dist/proxy/otelLogSink.js +174 -27
  15. package/dist/proxy/otlpLogTransport.d.ts +4 -2
  16. package/dist/proxy/otlpLogTransport.js +22 -7
  17. package/dist/proxy/requestLogger.js +11 -3
  18. package/dist/proxy/restartControl.js +18 -3
  19. package/dist/proxy/rollingProxyServer.js +48 -1
  20. package/dist/proxy/rollingWorkerProcess.js +87 -10
  21. package/dist/proxy/rollingWorkerProtocol.js +4 -2
  22. package/dist/proxy/rollingWorkerSupervisor.js +47 -10
  23. package/dist/proxy/socketWorkerRuntime.js +90 -4
  24. package/dist/proxy/updateChecker.d.ts +3 -3
  25. package/dist/proxy/updateChecker.js +16 -9
  26. package/dist/proxy/updateCoordinator.d.ts +10 -1
  27. package/dist/proxy/updateCoordinator.js +68 -1
  28. package/dist/proxy/updateState.d.ts +2 -0
  29. package/dist/proxy/updateState.js +15 -0
  30. package/dist/proxy/vertexAnthropicFallback.d.ts +17 -1
  31. package/dist/proxy/vertexAnthropicFallback.js +25 -1
  32. package/dist/server/routes/claudeProxyRoutes.d.ts +17 -0
  33. package/dist/server/routes/claudeProxyRoutes.js +53 -5
  34. package/dist/types/cli.d.ts +18 -0
  35. package/dist/types/providers.d.ts +8 -0
  36. package/dist/types/proxy.d.ts +117 -7
  37. package/dist/utils/anthropicCacheBreakpoints.d.ts +22 -1
  38. package/dist/utils/anthropicCacheBreakpoints.js +113 -0
  39. package/dist/utils/pricing.js +69 -2
  40. package/docs-site/static/search-index.json +1 -1
  41. package/package.json +1 -1
  42. package/scripts/observability/NATIVE-DURABLE.md +68 -0
  43. package/scripts/observability/otel-collector.proxy-native-durable.yaml +2 -2
  44. 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
+ }
@@ -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-08-21). Cache multipliers are the documented ones: a 5-minute
82
- // cache write is 1.25x base input, a cache hit 0.1x.
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,