@juspay/neurolink 9.84.2 → 9.85.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/browser/neurolink.min.js +410 -375
  3. package/dist/cli/factories/commandFactory.d.ts +17 -0
  4. package/dist/cli/factories/commandFactory.js +254 -0
  5. package/dist/cli/parser.js +2 -0
  6. package/dist/cli/utils/skillsFlags.d.ts +10 -0
  7. package/dist/cli/utils/skillsFlags.js +22 -0
  8. package/dist/index.d.ts +5 -0
  9. package/dist/index.js +6 -0
  10. package/dist/lib/index.d.ts +5 -0
  11. package/dist/lib/index.js +6 -0
  12. package/dist/lib/neurolink.d.ts +28 -0
  13. package/dist/lib/neurolink.js +117 -0
  14. package/dist/lib/server/routes/agentRoutes.js +156 -1
  15. package/dist/lib/server/routes/claudeProxyRoutes.d.ts +39 -1
  16. package/dist/lib/server/routes/claudeProxyRoutes.js +300 -41
  17. package/dist/lib/server/utils/validation.d.ts +32 -0
  18. package/dist/lib/server/utils/validation.js +18 -0
  19. package/dist/lib/session/globalSessionState.d.ts +10 -1
  20. package/dist/lib/session/globalSessionState.js +18 -0
  21. package/dist/lib/skills/skillMatcher.d.ts +20 -0
  22. package/dist/lib/skills/skillMatcher.js +80 -0
  23. package/dist/lib/skills/skillStoreRedis.d.ts +22 -0
  24. package/dist/lib/skills/skillStoreRedis.js +98 -0
  25. package/dist/lib/skills/skillStoreS3.d.ts +41 -0
  26. package/dist/lib/skills/skillStoreS3.js +233 -0
  27. package/dist/lib/skills/skillStores.d.ts +44 -0
  28. package/dist/lib/skills/skillStores.js +252 -0
  29. package/dist/lib/skills/skillTools.d.ts +19 -0
  30. package/dist/lib/skills/skillTools.js +340 -0
  31. package/dist/lib/skills/skillsManager.d.ts +54 -0
  32. package/dist/lib/skills/skillsManager.js +220 -0
  33. package/dist/lib/types/config.d.ts +10 -0
  34. package/dist/lib/types/generate.d.ts +8 -0
  35. package/dist/lib/types/index.d.ts +1 -0
  36. package/dist/lib/types/index.js +1 -0
  37. package/dist/lib/types/proxy.d.ts +30 -2
  38. package/dist/lib/types/skills.d.ts +296 -0
  39. package/dist/lib/types/skills.js +17 -0
  40. package/dist/lib/types/stream.d.ts +8 -0
  41. package/dist/neurolink.d.ts +28 -0
  42. package/dist/neurolink.js +117 -0
  43. package/dist/server/routes/agentRoutes.js +156 -1
  44. package/dist/server/routes/claudeProxyRoutes.d.ts +39 -1
  45. package/dist/server/routes/claudeProxyRoutes.js +300 -41
  46. package/dist/server/utils/validation.d.ts +32 -0
  47. package/dist/server/utils/validation.js +18 -0
  48. package/dist/session/globalSessionState.d.ts +10 -1
  49. package/dist/session/globalSessionState.js +18 -0
  50. package/dist/skills/skillMatcher.d.ts +20 -0
  51. package/dist/skills/skillMatcher.js +79 -0
  52. package/dist/skills/skillStoreRedis.d.ts +22 -0
  53. package/dist/skills/skillStoreRedis.js +97 -0
  54. package/dist/skills/skillStoreS3.d.ts +41 -0
  55. package/dist/skills/skillStoreS3.js +232 -0
  56. package/dist/skills/skillStores.d.ts +44 -0
  57. package/dist/skills/skillStores.js +251 -0
  58. package/dist/skills/skillTools.d.ts +19 -0
  59. package/dist/skills/skillTools.js +339 -0
  60. package/dist/skills/skillsManager.d.ts +54 -0
  61. package/dist/skills/skillsManager.js +219 -0
  62. package/dist/types/config.d.ts +10 -0
  63. package/dist/types/generate.d.ts +8 -0
  64. package/dist/types/index.d.ts +1 -0
  65. package/dist/types/index.js +1 -0
  66. package/dist/types/proxy.d.ts +30 -2
  67. package/dist/types/skills.d.ts +296 -0
  68. package/dist/types/skills.js +16 -0
  69. package/dist/types/stream.d.ts +8 -0
  70. package/package.json +2 -1
@@ -7,7 +7,34 @@ import { ProviderFactory } from "../../factories/providerFactory.js";
7
7
  import { withSpan } from "../../telemetry/withSpan.js";
8
8
  import { tracers } from "../../telemetry/tracers.js";
9
9
  import { createStreamRedactor } from "../utils/redaction.js";
10
- import { AgentExecuteRequestSchema, createErrorResponse as createError, EmbedManyRequestSchema, EmbedRequestSchema, validateRequest, } from "../utils/validation.js";
10
+ import { AgentExecuteRequestSchema, createErrorResponse as createError, EmbedManyRequestSchema, EmbedRequestSchema, SkillCreateRequestSchema, SkillUpdateRequestSchema, validateRequest, } from "../utils/validation.js";
11
+ /**
12
+ * Resolve the skills manager from the server's NeuroLink instance, or a
13
+ * 503 error response when skills are not configured on this server.
14
+ */
15
+ function resolveSkillsManager(ctx) {
16
+ const manager = ctx.neurolink.getSkillsManager();
17
+ if (!manager) {
18
+ return createError("SKILLS_UNAVAILABLE", "Skills are not enabled on this server — construct NeuroLink with a `skills` config.", undefined, ctx.requestId);
19
+ }
20
+ return manager;
21
+ }
22
+ /**
23
+ * Resolve the skills manager for a *mutating* route, or an error response when
24
+ * skills aren't configured (503) or mutations are disabled (allowMutations is
25
+ * not true). The LLM tools are already registration-gated; this applies the
26
+ * same switch to the REST create/update/delete endpoints.
27
+ */
28
+ function resolveMutableSkillsManager(ctx) {
29
+ const manager = resolveSkillsManager(ctx);
30
+ if ("error" in manager) {
31
+ return manager;
32
+ }
33
+ if (!manager.mutationsAllowed) {
34
+ return createError("SKILLS_MUTATIONS_DISABLED", "Skill mutations are disabled on this server \u2014 construct NeuroLink with `skills.allowMutations: true` to enable create/update/delete.", undefined, ctx.requestId);
35
+ }
36
+ return manager;
37
+ }
11
38
  /**
12
39
  * Create agent routes
13
40
  */
@@ -239,6 +266,134 @@ export function createAgentRoutes(basePath = "/api") {
239
266
  description: "Generate embeddings for multiple texts in a batch",
240
267
  tags: ["agent", "embeddings"],
241
268
  },
269
+ {
270
+ method: "GET",
271
+ path: `${basePath}/agent/skills`,
272
+ handler: async (ctx) => {
273
+ const manager = resolveSkillsManager(ctx);
274
+ if ("error" in manager) {
275
+ return manager;
276
+ }
277
+ try {
278
+ const skills = await manager.list(ctx.query.scopeId);
279
+ return { skills, count: skills.length };
280
+ }
281
+ catch (error) {
282
+ return createError("EXECUTION_FAILED", error instanceof Error ? error.message : "Skills listing failed", undefined, ctx.requestId);
283
+ }
284
+ },
285
+ description: "List active skills (index only — no instructions). Optional ?scopeId= filter.",
286
+ tags: ["agent", "skills"],
287
+ },
288
+ {
289
+ method: "GET",
290
+ path: `${basePath}/agent/skills/:id`,
291
+ handler: async (ctx) => {
292
+ const manager = resolveSkillsManager(ctx);
293
+ if ("error" in manager) {
294
+ return manager;
295
+ }
296
+ try {
297
+ const skill = await manager.get(ctx.params.id);
298
+ if (!skill) {
299
+ return createError("NOT_FOUND", `Skill "${ctx.params.id}" not found`, undefined, ctx.requestId);
300
+ }
301
+ return skill;
302
+ }
303
+ catch (error) {
304
+ return createError("EXECUTION_FAILED", error instanceof Error ? error.message : "Skill lookup failed", undefined, ctx.requestId);
305
+ }
306
+ },
307
+ description: "Fetch one skill (by id or exact name) with instructions",
308
+ tags: ["agent", "skills"],
309
+ },
310
+ {
311
+ method: "POST",
312
+ path: `${basePath}/agent/skills`,
313
+ handler: async (ctx) => {
314
+ const manager = resolveMutableSkillsManager(ctx);
315
+ if ("error" in manager) {
316
+ return manager;
317
+ }
318
+ const validation = validateRequest(SkillCreateRequestSchema, ctx.body, ctx.requestId);
319
+ if (!validation.success) {
320
+ return validation.error;
321
+ }
322
+ const { requestedBy, ...skill } = validation.data;
323
+ try {
324
+ const result = await manager.requestMutation({
325
+ type: "create",
326
+ skill,
327
+ // Authenticated identity wins over caller-supplied attribution.
328
+ ...(ctx.user?.id || requestedBy
329
+ ? { requestedBy: ctx.user?.id ?? requestedBy }
330
+ : {}),
331
+ });
332
+ return result;
333
+ }
334
+ catch (error) {
335
+ return createError("EXECUTION_FAILED", error instanceof Error ? error.message : "Skill create failed", undefined, ctx.requestId);
336
+ }
337
+ },
338
+ description: "Create a skill (routed through the host's onMutationRequest gate when configured)",
339
+ tags: ["agent", "skills"],
340
+ },
341
+ {
342
+ method: "PATCH",
343
+ path: `${basePath}/agent/skills/:id`,
344
+ handler: async (ctx) => {
345
+ const manager = resolveMutableSkillsManager(ctx);
346
+ if ("error" in manager) {
347
+ return manager;
348
+ }
349
+ const validation = validateRequest(SkillUpdateRequestSchema, ctx.body, ctx.requestId);
350
+ if (!validation.success) {
351
+ return validation.error;
352
+ }
353
+ const { requestedBy, ...patch } = validation.data;
354
+ try {
355
+ const result = await manager.requestMutation({
356
+ type: "update",
357
+ skillId: ctx.params.id,
358
+ patch,
359
+ ...(ctx.user?.id || requestedBy
360
+ ? { requestedBy: ctx.user?.id ?? requestedBy }
361
+ : {}),
362
+ });
363
+ return result;
364
+ }
365
+ catch (error) {
366
+ const message = error instanceof Error ? error.message : "Skill update failed";
367
+ return createError(message.includes("not found") ? "NOT_FOUND" : "EXECUTION_FAILED", message, undefined, ctx.requestId);
368
+ }
369
+ },
370
+ description: "Update a skill (patch semantics; version is bumped)",
371
+ tags: ["agent", "skills"],
372
+ },
373
+ {
374
+ method: "DELETE",
375
+ path: `${basePath}/agent/skills/:id`,
376
+ handler: async (ctx) => {
377
+ const manager = resolveMutableSkillsManager(ctx);
378
+ if ("error" in manager) {
379
+ return manager;
380
+ }
381
+ try {
382
+ const result = await manager.requestMutation({
383
+ type: "delete",
384
+ skillId: ctx.params.id,
385
+ ...(ctx.user?.id ? { requestedBy: ctx.user.id } : {}),
386
+ });
387
+ return result;
388
+ }
389
+ catch (error) {
390
+ const message = error instanceof Error ? error.message : "Skill delete failed";
391
+ return createError(message.includes("not found") ? "NOT_FOUND" : "EXECUTION_FAILED", message, undefined, ctx.requestId);
392
+ }
393
+ },
394
+ description: "Soft-delete (deprecate) a skill",
395
+ tags: ["agent", "skills"],
396
+ },
242
397
  ],
243
398
  };
244
399
  }
@@ -11,7 +11,7 @@
11
11
  */
12
12
  import { buildTranslationOptions } from "../../proxy/proxyTranslationEngine.js";
13
13
  import type { ModelRouter } from "../../proxy/modelRouter.js";
14
- import type { ParsedClaudeError, ProxyPassthroughAccount, RouteGroup, RuntimeAccountState } from "../../types/index.js";
14
+ import type { AccountCooldownPlan, AccountQuota, ParsedClaudeError, ProxyPassthroughAccount, RouteGroup, RuntimeAccountState } from "../../types/index.js";
15
15
  /** Resolve the configured primary's stable key to its current index in the
16
16
  * request's enabledAccounts list. Returns 0 (insertion-order fallback) when
17
17
  * no key is configured or the key cannot be matched (account disabled/
@@ -23,6 +23,41 @@ declare function resolveHomeIndex(enabledAccounts: ProxyPassthroughAccount[]): n
23
23
  * account once its rate limit window expires. Called at the start of each
24
24
  * request. Home is resolved fresh per call via resolveHomeIndex. */
25
25
  declare function maybeResetPrimaryToHome(enabledAccounts: ProxyPassthroughAccount[]): void;
26
+ /** Convert an Anthropic unified-window reset (Unix epoch SECONDS, per the
27
+ * `anthropic-ratelimit-unified-*-reset` headers) into epoch-ms. Tolerates a
28
+ * value already expressed in ms (some intermediaries normalise it). Returns
29
+ * undefined for absent/zero/past-or-garbage timestamps so callers can fall
30
+ * back to retry-after. */
31
+ declare function resetEpochToMs(resetEpoch: number | undefined, now: number): number | undefined;
32
+ /**
33
+ * Decide how to cool an account after a genuine (non-anti-abuse) 429.
34
+ *
35
+ * The unified subscription limits expose per-window status + reset:
36
+ * - weekly (7d) "rejected" → hard cap for the week; cool until the 7d reset.
37
+ * - session (5h) "rejected" → paced out for this session; cool until the 5h reset.
38
+ * Both mean "retrying this account is futile until its window resets" → rotate
39
+ * immediately (no same-account retries) and park the account until the ACTUAL
40
+ * reset — never the legacy 60s hardcap that let us re-hammer a spent account.
41
+ *
42
+ * Anything else (window still "allowed" but momentarily 429'd — a per-minute
43
+ * burst / acceleration limit) is transient: honor retry-after as a floor,
44
+ * allow a couple of jittered same-account retries, then a short cooldown.
45
+ */
46
+ declare function planCooldownFor429(quota: AccountQuota | null, retryAfterMs: number, now: number): AccountCooldownPlan;
47
+ /**
48
+ * Order accounts to MAXIMIZE quota utilization (fill-first, smart order):
49
+ * spend the account whose window refreshes SOONEST first, so its about-to-reset
50
+ * allowance isn't wasted, then move to accounts with longer-dated resets.
51
+ *
52
+ * Priority among usable accounts:
53
+ * 1. soonest WEEKLY (7d) reset — the scarce, use-it-or-lose-it ceiling
54
+ * 2. soonest SESSION (5h) reset
55
+ * 3. highest weekly utilization — finish off the one closest to done
56
+ * Accounts with no quota data yet keep insertion order (stable sort) and sit
57
+ * after those with a known soonest reset. Cooling/rejected accounts sort last,
58
+ * soonest-back-to-service first, as last resort.
59
+ */
60
+ declare function orderAccountsByQuota(accounts: ProxyPassthroughAccount[], now: number): ProxyPassthroughAccount[];
26
61
  /**
27
62
  * Create Claude-compatible proxy routes.
28
63
  *
@@ -57,6 +92,9 @@ export declare function isTransientHttpFailure(status: number, errBody: string):
57
92
  export declare const __testHooks: {
58
93
  resolveHomeIndex: typeof resolveHomeIndex;
59
94
  maybeResetPrimaryToHome: typeof maybeResetPrimaryToHome;
95
+ planCooldownFor429: typeof planCooldownFor429;
96
+ orderAccountsByQuota: typeof orderAccountsByQuota;
97
+ resetEpochToMs: typeof resetEpochToMs;
60
98
  setConfiguredPrimaryAccountKey: (key: string | undefined) => void;
61
99
  getConfiguredPrimaryAccountKey: () => string | undefined;
62
100
  setPrimaryAccountIndex: (index: number) => void;