@juspay/neurolink 12.25.4 → 12.26.0

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 (35) hide show
  1. package/CHANGELOG.md +3 -3
  2. package/dist/browser/neurolink.min.js +372 -372
  3. package/dist/cli/commands/decide.d.ts +2 -1
  4. package/dist/cli/commands/decide.js +4 -2
  5. package/dist/cli/commands/setup.js +2 -1
  6. package/dist/cli/factories/commandFactory.js +1 -1
  7. package/dist/cli/utils/classifierRouterFlags.js +1 -1
  8. package/dist/constants/enums.d.ts +15 -0
  9. package/dist/constants/enums.js +16 -0
  10. package/dist/core/baseProvider.js +2 -2
  11. package/dist/factories/providerDescriptors.d.ts +16 -7
  12. package/dist/factories/providerDescriptors.js +97 -15
  13. package/dist/factories/providerRegistry.js +9 -1
  14. package/dist/models/manifestRegistry.js +2 -0
  15. package/dist/models/manifests/laya.d.ts +12 -0
  16. package/dist/models/manifests/laya.js +54 -0
  17. package/dist/neurolink.js +8 -3
  18. package/dist/providers/anthropic/client.js +17 -1
  19. package/dist/providers/laya.d.ts +40 -0
  20. package/dist/providers/laya.js +170 -0
  21. package/dist/providers/systemOneDecision.d.ts +102 -0
  22. package/dist/providers/systemOneDecision.js +443 -0
  23. package/dist/providers/typesafe.d.ts +32 -47
  24. package/dist/providers/typesafe.js +64 -386
  25. package/dist/routing/classifierRouter.d.ts +2 -2
  26. package/dist/routing/classifierRouter.js +10 -8
  27. package/dist/types/classifierRouter.d.ts +13 -3
  28. package/dist/types/cli.d.ts +3 -2
  29. package/dist/types/decision.d.ts +29 -0
  30. package/dist/types/providers.d.ts +20 -1
  31. package/dist/utils/modelChoices.js +21 -1
  32. package/dist/utils/providerConfig.d.ts +5 -0
  33. package/dist/utils/providerConfig.js +17 -0
  34. package/docs-site/static/search-index.json +24 -10
  35. package/package.json +3 -1
@@ -8,7 +8,8 @@
8
8
  * for the full vocabulary.
9
9
  *
10
10
  * Credentials are env-only here, exactly as every other CLI command: the
11
- * decision provider (TypeSafe) reads `TYPESAFE_API_KEY` itself.
11
+ * decision provider reads its own settings (TYPESAFE_API_KEY, or LAYA_API_KEY
12
+ * and LAYA_BASE_URL) itself.
12
13
  */
13
14
  import type { CommandModule } from "yargs";
14
15
  import type { CliDecideArgs } from "../../types/index.js";
@@ -8,11 +8,13 @@
8
8
  * for the full vocabulary.
9
9
  *
10
10
  * Credentials are env-only here, exactly as every other CLI command: the
11
- * decision provider (TypeSafe) reads `TYPESAFE_API_KEY` itself.
11
+ * decision provider reads its own settings (TYPESAFE_API_KEY, or LAYA_API_KEY
12
+ * and LAYA_BASE_URL) itself.
12
13
  */
13
14
  import chalk from "chalk";
14
15
  import ora from "ora";
15
16
  import fs from "node:fs";
17
+ import { describeDecisionProviderKeys } from "../../factories/providerDescriptors.js";
16
18
  import { NeuroLink } from "../../neurolink.js";
17
19
  import { readDecisionChoice } from "../../utils/decisionAnswers.js";
18
20
  import { calculateCost, hasPricing } from "../../utils/pricing.js";
@@ -87,7 +89,7 @@ function describeDecideError(error) {
87
89
  }
88
90
  const message = error instanceof Error ? error.message : String(error);
89
91
  if (message.includes("No decision provider is configured")) {
90
- return "No decision provider is configured. Set TYPESAFE_API_KEY, or AI_GATEWAY_API_KEY for the Vercel AI Gateway route.";
92
+ return `No decision provider is configured. Set ${describeDecisionProviderKeys()}.`;
91
93
  }
92
94
  return message;
93
95
  }
@@ -20,7 +20,7 @@ import { handleGCPSetup } from "./setup-gcp.js";
20
20
  import { handleHuggingFaceSetup } from "./setup-huggingface.js";
21
21
  import { handleMistralSetup } from "./setup-mistral.js";
22
22
  import { PROVIDER_DESCRIPTORS_BY_NAME } from "../../factories/providerDescriptors.js";
23
- import { createCohereConfig, createDeepSeekConfig, createIdeogramConfig, createJinaConfig, createNvidiaNimConfig, createOpenAICompatibleConfig, createRecraftConfig, createReplicateConfig, createStabilityConfig, createVoyageConfig, createTypeSafeConfig, satisfiesFallbacks, } from "../../utils/providerConfig.js";
23
+ import { createCohereConfig, createDeepSeekConfig, createIdeogramConfig, createJinaConfig, createNvidiaNimConfig, createOpenAICompatibleConfig, createRecraftConfig, createReplicateConfig, createStabilityConfig, createVoyageConfig, createTypeSafeConfig, createLayaConfig, satisfiesFallbacks, } from "../../utils/providerConfig.js";
24
24
  import { getCatalogJsonEntries, buildCatalogConfigOptions, } from "../../providers/catalog/loader.js";
25
25
  // Provider information database
26
26
  const PROVIDERS = [
@@ -169,6 +169,7 @@ export const EXTRA_PROVIDER_CONFIGS = {
169
169
  ideogram: createIdeogramConfig(),
170
170
  recraft: createRecraftConfig(),
171
171
  typesafe: createTypeSafeConfig(),
172
+ laya: createLayaConfig(),
172
173
  ...Object.fromEntries(getCatalogJsonEntries()
173
174
  .filter((e) => e.id !== "mistral")
174
175
  .map((e) => [e.id, buildCatalogConfigOptions(e)])),
@@ -593,7 +593,7 @@ export class CLICommandFactory {
593
593
  },
594
594
  classifierStrategy: {
595
595
  type: "string",
596
- description: "Classifier strategy: 'auto' (default — 'jev' when TYPESAFE_API_KEY is set, else 'heuristic'), 'heuristic' (no LLM), 'llm' (a cheap model picks per prompt), or 'jev' (TypeSafe System One, ~400ms with calibrated confidence).",
596
+ description: "Classifier strategy: 'auto' (default — 'jev' when a decision provider is configured, such as TYPESAFE_API_KEY, or LAYA_API_KEY with LAYA_BASE_URL, else 'heuristic'), 'heuristic' (no LLM), 'llm' (a cheap model picks per prompt), or 'jev' (a System One decision model — TypeSafe Jev, or Laya — with calibrated confidence).",
597
597
  choices: ["auto", "heuristic", "llm", "jev"],
598
598
  alias: "classifier-strategy",
599
599
  },
@@ -37,7 +37,7 @@ export function buildClassifierRouterConfigFromCli(flags) {
37
37
  if (!flags.classifierRouter) {
38
38
  return undefined;
39
39
  }
40
- // Defaults to "auto", which resolves to "jev" when TYPESAFE_API_KEY is set
40
+ // Defaults to "auto", which resolves to "jev" when a decision provider's key is set
41
41
  // and "heuristic" otherwise — so a configured key upgrades CLI routing with
42
42
  // no flag change, and an unset one behaves exactly as before.
43
43
  const strategy = isStrategyKind(flags.classifierStrategy)
@@ -44,6 +44,8 @@ export declare enum AIProviderName {
44
44
  RECRAFT = "recraft",
45
45
  /** TypeSafe (Jev) — serves the `decide` inference type only. */
46
46
  TYPESAFE = "typesafe",
47
+ /** Laya (Convai, open weights) — serves the `decide` inference type only. */
48
+ LAYA = "laya",
47
49
  AUTO = "auto"
48
50
  }
49
51
  /**
@@ -1047,3 +1049,16 @@ export declare enum TypeSafeModels {
1047
1049
  JEV_LATEST = "jev-latest",
1048
1050
  JEV_PREVIEW = "jev-preview"
1049
1051
  }
1052
+ /**
1053
+ * Laya checkpoints. Hand-written: Laya is a Tier-3 provider, so it is not in
1054
+ * the provider catalog and codegen never touches this.
1055
+ *
1056
+ * `auto` sends no model, which lets Laya's own router pick a checkpoint by
1057
+ * the detected language of the state.
1058
+ */
1059
+ export declare enum LayaModels {
1060
+ TYPED_DECISIONS = "typed-decisions",
1061
+ ENGLISH = "english",
1062
+ MULTILINGUAL = "multilingual",
1063
+ AUTO = "auto"
1064
+ }
@@ -50,6 +50,8 @@ export var AIProviderName;
50
50
  AIProviderName["RECRAFT"] = "recraft";
51
51
  /** TypeSafe (Jev) — serves the `decide` inference type only. */
52
52
  AIProviderName["TYPESAFE"] = "typesafe";
53
+ /** Laya (Convai, open weights) — serves the `decide` inference type only. */
54
+ AIProviderName["LAYA"] = "laya";
53
55
  AIProviderName["AUTO"] = "auto";
54
56
  })(AIProviderName || (AIProviderName = {}));
55
57
  /**
@@ -1295,3 +1297,17 @@ export var TypeSafeModels;
1295
1297
  TypeSafeModels["JEV_LATEST"] = "jev-latest";
1296
1298
  TypeSafeModels["JEV_PREVIEW"] = "jev-preview";
1297
1299
  })(TypeSafeModels || (TypeSafeModels = {}));
1300
+ /**
1301
+ * Laya checkpoints. Hand-written: Laya is a Tier-3 provider, so it is not in
1302
+ * the provider catalog and codegen never touches this.
1303
+ *
1304
+ * `auto` sends no model, which lets Laya's own router pick a checkpoint by
1305
+ * the detected language of the state.
1306
+ */
1307
+ export var LayaModels;
1308
+ (function (LayaModels) {
1309
+ LayaModels["TYPED_DECISIONS"] = "typed-decisions";
1310
+ LayaModels["ENGLISH"] = "english";
1311
+ LayaModels["MULTILINGUAL"] = "multilingual";
1312
+ LayaModels["AUTO"] = "auto";
1313
+ })(LayaModels || (LayaModels = {}));
@@ -1,7 +1,7 @@
1
1
  import { context, SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
2
2
  import { directAgentTools } from "../agent/directTools.js";
3
3
  import { defaultProviderFor } from "../factories/mediaHandlerCatalog.js";
4
- import { PROVIDER_DESCRIPTORS_BY_NAME } from "../factories/providerDescriptors.js";
4
+ import { DECISION_PROVIDERS, PROVIDER_DESCRIPTORS_BY_NAME, } from "../factories/providerDescriptors.js";
5
5
  import { MiddlewareFactory } from "../middleware/factory.js";
6
6
  import { modelSupports } from "../models/modelRegistry.js";
7
7
  import { resolveRequestKind } from "./resolveRequestKind.js";
@@ -1854,7 +1854,7 @@ export class BaseProvider {
1854
1854
  async decide(_request) {
1855
1855
  logger.warn(`decide() called on ${this.providerName}, which does not serve the decide inference type`);
1856
1856
  throw new Error(`The decide inference type is not supported by the ${this.providerName} provider. ` +
1857
- `Supported providers: typesafe. A provider declares this capability with ` +
1857
+ `Supported providers: ${DECISION_PROVIDERS.map((d) => d.name).join(", ")}. A provider declares this capability with ` +
1858
1858
  `"decide" in its descriptor's inferenceKinds.`);
1859
1859
  }
1860
1860
  /**
@@ -1,5 +1,5 @@
1
1
  import { AIProviderName } from "../constants/enums.js";
2
- import type { ProviderDescriptor } from "../types/index.js";
2
+ import type { NeurolinkCredentials, ProviderDescriptor } from "../types/index.js";
3
3
  /**
4
4
  * Single source of truth for provider identity, credentials, defaults, and
5
5
  * runtime behavior classification — the hand-maintained providers plus the
@@ -21,11 +21,20 @@ export declare const PROVIDER_ALIAS_INDEX: ReadonlyMap<string, AIProviderName>;
21
21
  */
22
22
  export declare const DECISION_PROVIDERS: readonly ProviderDescriptor[];
23
23
  /**
24
- * The decision provider to use when a caller names none: the first one whose
25
- * primary credential env var is actually set.
24
+ * The decision provider to use when a caller names none: the first
25
+ * DECISION_PROVIDERS entry that is fully configured, from the environment or
26
+ * from `credentials`.
26
27
  *
27
- * This is where "if somebody sets the key, we start using it" is implemented.
28
- * Returns undefined when none is configured, which every internal consumer
29
- * treats as "carry on exactly as before".
28
+ * This is where "if somebody configures it, we start using it" is
29
+ * implemented. Returns undefined when none is configured, which every
30
+ * internal consumer treats as "carry on exactly as before".
30
31
  */
31
- export declare function resolveDefaultDecisionProvider(): string | undefined;
32
+ export declare function resolveDefaultDecisionProvider(credentials?: NeurolinkCredentials): string | undefined;
33
+ /**
34
+ * The variables that would configure each decision provider, one clause per
35
+ * provider in precedence order, e.g. "TYPESAFE_API_KEY or AI_GATEWAY_API_KEY
36
+ * for typesafe, or LAYA_API_KEY and LAYA_BASE_URL for laya". Derived from
37
+ * DECISION_PROVIDERS so a new decision provider appears in every "nothing is
38
+ * configured" message without anyone editing one.
39
+ */
40
+ export declare function describeDecisionProviderKeys(): string;
@@ -1,5 +1,5 @@
1
1
  import { AIProviderName } from "../constants/enums.js";
2
- import { GoogleAIModels, OpenAIModels, AnthropicModels, VertexModels, OllamaModels, LiteLLMModels, NvidiaNimModels, OpenRouterModels, CohereModels, VoyageModels, TypeSafeModels, JinaModels, StabilityModels, IdeogramModels, RecraftModels, ReplicateModels, } from "../constants/enums.js";
2
+ import { GoogleAIModels, OpenAIModels, AnthropicModels, VertexModels, OllamaModels, LiteLLMModels, NvidiaNimModels, OpenRouterModels, CohereModels, VoyageModels, TypeSafeModels, LayaModels, JinaModels, StabilityModels, IdeogramModels, RecraftModels, ReplicateModels, } from "../constants/enums.js";
3
3
  import { API_KEY_FORMATS } from "../utils/providerConfig.js";
4
4
  import { getCatalogJsonEntries, catalogCredentialsKey, catalogEnvVar, } from "../providers/catalog/loader.js";
5
5
  import { DEFAULT_INFERENCE_KINDS } from "../types/index.js";
@@ -451,6 +451,56 @@ const HAND_DESCRIPTORS = [
451
451
  timeouts: { decideMs: 5000 },
452
452
  setupUrl: "https://console.typesafe.ai/keys",
453
453
  },
454
+ // Laya MUST stay after TypeSafe. resolveDefaultDecisionProvider() returns
455
+ // the first configured DECISION_PROVIDERS entry, in this order, so a host
456
+ // configured for both keeps Jev for every built-in consumer and reaches
457
+ // Laya only by naming it. Reordering these two silently changes which model
458
+ // routes, compacts and plans for every such host.
459
+ {
460
+ name: AIProviderName.LAYA,
461
+ aliases: [],
462
+ credentialsKey: "laya",
463
+ envVars: {
464
+ apiKey: "LAYA_API_KEY",
465
+ baseURL: "LAYA_BASE_URL",
466
+ // Laya has no built-in endpoint (it is self-hosted or behind a proxy),
467
+ // so a key is useless without a base URL. Both are required for it to
468
+ // count as configured, from the environment or credentials.laya.
469
+ extraRequired: ["LAYA_BASE_URL"],
470
+ model: "LAYA_MODEL",
471
+ },
472
+ defaultModel: LayaModels.TYPED_DECISIONS,
473
+ // Serves only `decide`, like TypeSafe — the one declaration that keeps it
474
+ // out of every generation code path.
475
+ inferenceKinds: ["decide"],
476
+ toolSupport: "none",
477
+ localRuntime: false,
478
+ healthCheck: "env-only",
479
+ // Deliberately NO autoSelectPriority / autoSelectPreference /
480
+ // defaultHealthSweepPriority, for the same reason as TypeSafe above.
481
+ timeouts: { decideMs: 5000 },
482
+ // Laya's encoders cut the state off silently past their window (measured
483
+ // live: a 60,000-character state answered 200 on 1,024 tokens). 768 is
484
+ // the 1,024-token window minus the 256-token budget Laya reserves for a
485
+ // question and its options; 320 is the English checkpoint's 512 minus
486
+ // 192. `auto` may route to English, and an unlisted name (Laya's server
487
+ // accepts aliases such as `en`) could be any checkpoint, so both get 320.
488
+ // 64 is the question cap in Laya's own server. Non-ASCII rates were
489
+ // measured live: Chinese is ~1.4 tokens per character on the English
490
+ // tokenizer (typed-decisions, english) and ~0.56 on multilingual.
491
+ decisionLimits: {
492
+ maxStateTokens: 320,
493
+ maxQuestions: 64,
494
+ nonAsciiTokensPerChar: 1.5,
495
+ models: {
496
+ "typed-decisions": { maxStateTokens: 768 },
497
+ multilingual: { maxStateTokens: 768, nonAsciiTokensPerChar: 0.6 },
498
+ english: { maxStateTokens: 320 },
499
+ auto: { maxStateTokens: 320 },
500
+ },
501
+ },
502
+ setupUrl: "https://github.com/NandhaKishorM/laya",
503
+ },
454
504
  ];
455
505
  /**
456
506
  * Builds a ProviderDescriptor for every JSON-catalog provider. Every field
@@ -554,20 +604,52 @@ export const PROVIDER_ALIAS_INDEX = new Map(PROVIDER_DESCRIPTORS.flatMap((d) =>
554
604
  */
555
605
  export const DECISION_PROVIDERS = PROVIDER_DESCRIPTORS.filter((d) => (d.inferenceKinds ?? DEFAULT_INFERENCE_KINDS).includes("decide"));
556
606
  /**
557
- * The decision provider to use when a caller names none: the first one whose
558
- * primary credential env var is actually set.
607
+ * Whether a decision provider is fully configured: its key and every
608
+ * extraRequired variable are set, each either in the environment or in
609
+ * `credentials` — the same config a caller passes to
610
+ * `new NeuroLink({ credentials })` or per call. Whitespace counts as unset.
611
+ */
612
+ function isDecisionProviderConfigured(descriptor, credentials) {
613
+ const isSet = (value) => typeof value === "string" && value.trim() !== "";
614
+ const inEnv = (name) => name !== undefined && isSet(process.env[name]);
615
+ const slice = descriptor.credentialsKey
616
+ ? credentials?.[descriptor.credentialsKey]
617
+ : undefined;
618
+ // `gatewayApiKey` is TypeSafe's config form of AI_GATEWAY_API_KEY.
619
+ const hasKey = [descriptor.envVars.apiKey, ...(descriptor.envVars.fallbacks ?? [])].some(inEnv) ||
620
+ isSet(slice?.apiKey) ||
621
+ isSet(slice?.gatewayApiKey);
622
+ // A required base URL can also come from credentials.<key>.baseURL.
623
+ const hasRequired = (descriptor.envVars.extraRequired ?? []).every((name) => inEnv(name) ||
624
+ (name === descriptor.envVars.baseURL && isSet(slice?.baseURL)));
625
+ return hasKey && hasRequired;
626
+ }
627
+ /**
628
+ * The decision provider to use when a caller names none: the first
629
+ * DECISION_PROVIDERS entry that is fully configured, from the environment or
630
+ * from `credentials`.
559
631
  *
560
- * This is where "if somebody sets the key, we start using it" is implemented.
561
- * Returns undefined when none is configured, which every internal consumer
562
- * treats as "carry on exactly as before".
632
+ * This is where "if somebody configures it, we start using it" is
633
+ * implemented. Returns undefined when none is configured, which every
634
+ * internal consumer treats as "carry on exactly as before".
563
635
  */
564
- export function resolveDefaultDecisionProvider() {
565
- for (const descriptor of DECISION_PROVIDERS) {
566
- const primary = descriptor.envVars.apiKey;
567
- const candidates = [primary, ...(descriptor.envVars.fallbacks ?? [])];
568
- if (candidates.some((v) => v && (process.env[v] ?? "").trim() !== "")) {
569
- return descriptor.name;
570
- }
571
- }
572
- return undefined;
636
+ export function resolveDefaultDecisionProvider(credentials) {
637
+ return DECISION_PROVIDERS.find((descriptor) => isDecisionProviderConfigured(descriptor, credentials))?.name;
638
+ }
639
+ /**
640
+ * The variables that would configure each decision provider, one clause per
641
+ * provider in precedence order, e.g. "TYPESAFE_API_KEY or AI_GATEWAY_API_KEY
642
+ * for typesafe, or LAYA_API_KEY and LAYA_BASE_URL for laya". Derived from
643
+ * DECISION_PROVIDERS so a new decision provider appears in every "nothing is
644
+ * configured" message without anyone editing one.
645
+ */
646
+ export function describeDecisionProviderKeys() {
647
+ return DECISION_PROVIDERS.map((descriptor) => {
648
+ const keys = [
649
+ descriptor.envVars.apiKey,
650
+ ...(descriptor.envVars.fallbacks ?? []),
651
+ ].filter((name) => typeof name === "string" && name !== "");
652
+ const required = descriptor.envVars.extraRequired ?? [];
653
+ return `${[keys.join(" or "), ...required].join(" and ")} for ${descriptor.name}`;
654
+ }).join(", or ");
573
655
  }
@@ -1,6 +1,6 @@
1
1
  import { ProviderFactory } from "./providerFactory.js";
2
2
  import { logger } from "../utils/logger.js";
3
- import { AIProviderName, GoogleAIModels, OpenAIModels, AnthropicModels, VertexModels, OllamaModels, LiteLLMModels, NvidiaNimModels, OpenRouterModels, CohereModels, VoyageModels, JinaModels, StabilityModels, IdeogramModels, RecraftModels, TypeSafeModels, ReplicateModels, } from "../constants/enums.js";
3
+ import { AIProviderName, GoogleAIModels, OpenAIModels, AnthropicModels, VertexModels, OllamaModels, LiteLLMModels, NvidiaNimModels, OpenRouterModels, CohereModels, VoyageModels, JinaModels, StabilityModels, IdeogramModels, RecraftModels, TypeSafeModels, LayaModels, ReplicateModels, } from "../constants/enums.js";
4
4
  import { PROVIDER_DESCRIPTORS_BY_NAME } from "./providerDescriptors.js";
5
5
  import { OPENAI_COMPAT_CATALOG } from "../providers/openaiCompatCatalog.js";
6
6
  import { providerChoicesFor } from "./mediaHandlerCatalog.js";
@@ -234,6 +234,14 @@ export class ProviderRegistry {
234
234
  const { TypeSafeProvider } = await import("../providers/typesafe.js");
235
235
  return new TypeSafeProvider(modelName, sdk, undefined, typesafeCreds);
236
236
  }, process.env.TYPESAFE_MODEL || TypeSafeModels.JEV_LATEST, ["jev", "typesafe-ai"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.TYPESAFE));
237
+ // Register Laya — the second `decide` provider, reached at whatever base
238
+ // URL its config names. Its descriptor declares inferenceKinds:
239
+ // ["decide"], so nothing in the generation fallback chain can reach it.
240
+ ProviderFactory.registerProvider(AIProviderName.LAYA, async (modelName, _providerName, sdk, _region, credentials) => {
241
+ const layaCreds = credentials;
242
+ const { LayaProvider } = await import("../providers/laya.js");
243
+ return new LayaProvider(modelName, sdk, undefined, layaCreds);
244
+ }, process.env.LAYA_MODEL || LayaModels.TYPED_DECISIONS, [], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.LAYA));
237
245
  logger.debug("All AI providers registered successfully");
238
246
  // ===== MEDIA HANDLER REGISTRATION =====
239
247
  // Single registration path (Task 11): each ecosystem barrel (voice,
@@ -20,6 +20,7 @@ import { llamacppManifest } from "./manifests/llamacpp.js";
20
20
  import { xaiManifest } from "./manifests/xai.js";
21
21
  import { groqManifest } from "./manifests/groq.js";
22
22
  import { typesafeManifest } from "./manifests/typesafe.js";
23
+ import { layaManifest } from "./manifests/laya.js";
23
24
  import { cohereManifest } from "./manifests/cohere.js";
24
25
  import { togetherAiManifest } from "./manifests/together-ai.js";
25
26
  import { fireworksManifest } from "./manifests/fireworks.js";
@@ -118,6 +119,7 @@ export const MANIFEST_REGISTRY = {
118
119
  xai: xaiManifest,
119
120
  groq: groqManifest,
120
121
  typesafe: typesafeManifest,
122
+ laya: layaManifest,
121
123
  cerebras: catalogManifest("cerebras"),
122
124
  sambanova: catalogManifest("sambanova"),
123
125
  cohere: cohereManifest,
@@ -0,0 +1,12 @@
1
+ import type { ProviderModelManifest } from "../../types/index.js";
2
+ /**
3
+ * Laya — the `decide` inference type, not text generation.
4
+ *
5
+ * `contextWindow` is each checkpoint's encoder window, the whole budget for
6
+ * the state plus one question's instructions and options. `auto` carries the
7
+ * English figure because Laya's router may pick the English checkpoint.
8
+ *
9
+ * `maxOutputTokens` is required by the manifest type but has no honest value
10
+ * for a model that emits no text, so a small non-zero figure is used.
11
+ */
12
+ export declare const layaManifest: ProviderModelManifest;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Laya — the `decide` inference type, not text generation.
3
+ *
4
+ * `contextWindow` is each checkpoint's encoder window, the whole budget for
5
+ * the state plus one question's instructions and options. `auto` carries the
6
+ * English figure because Laya's router may pick the English checkpoint.
7
+ *
8
+ * `maxOutputTokens` is required by the manifest type but has no honest value
9
+ * for a model that emits no text, so a small non-zero figure is used.
10
+ */
11
+ export const layaManifest = {
12
+ defaultContextWindow: 1024,
13
+ models: {
14
+ _default: {
15
+ aliases: [],
16
+ contextWindow: 1024,
17
+ maxOutputTokens: 256,
18
+ vision: false,
19
+ functionCalling: false,
20
+ },
21
+ "typed-decisions": {
22
+ aliases: [],
23
+ displayName: "Laya (typed decisions)",
24
+ contextWindow: 1024,
25
+ maxOutputTokens: 256,
26
+ vision: false,
27
+ functionCalling: false,
28
+ },
29
+ multilingual: {
30
+ aliases: [],
31
+ displayName: "Laya (multilingual)",
32
+ contextWindow: 1024,
33
+ maxOutputTokens: 256,
34
+ vision: false,
35
+ functionCalling: false,
36
+ },
37
+ english: {
38
+ aliases: [],
39
+ displayName: "Laya (English)",
40
+ contextWindow: 512,
41
+ maxOutputTokens: 256,
42
+ vision: false,
43
+ functionCalling: false,
44
+ },
45
+ auto: {
46
+ aliases: [],
47
+ displayName: "Laya (routed by language)",
48
+ contextWindow: 512,
49
+ maxOutputTokens: 256,
50
+ vision: false,
51
+ functionCalling: false,
52
+ },
53
+ },
54
+ };
package/dist/neurolink.js CHANGED
@@ -34,7 +34,7 @@ import { buildToolRoutingCatalog, buildRoutingQueryFromHistory, resolveToolRouti
34
34
  import { ToolRoutingCache } from "./core/toolRoutingCache.js";
35
35
  import { DEFAULT_RECENT_TURNS, KnowledgeGroundingEngine, } from "./knowledge/index.js";
36
36
  import { AIProviderFactory } from "./core/factory.js";
37
- import { resolveDefaultDecisionProvider } from "./factories/providerDescriptors.js";
37
+ import { describeDecisionProviderKeys, resolveDefaultDecisionProvider, } from "./factories/providerDescriptors.js";
38
38
  import { resolveRequestKind } from "./core/resolveRequestKind.js";
39
39
  import { createToolEventPayload } from "./core/toolEvents.js";
40
40
  import { ProviderFactory } from "./factories/providerFactory.js";
@@ -966,6 +966,8 @@ export class NeuroLink {
966
966
  // throwing, so an absent or broken decision provider leaves routing
967
967
  // exactly as it was.
968
968
  decide: (decideOptions) => this.tryDecide(decideOptions),
969
+ // Read lazily: `this.credentials` is assigned later in the constructor.
970
+ hasDecisionProvider: () => resolveDefaultDecisionProvider(this.credentials) !== undefined,
969
971
  logger: {
970
972
  debug: (message, meta) => logger.debug(message, meta),
971
973
  warn: (message, meta) => logger.warn(message, meta),
@@ -12700,9 +12702,12 @@ Current user's request: ${currentInput}`;
12700
12702
  * @throws when no decision provider is configured, or the call fails
12701
12703
  */
12702
12704
  async decide(options) {
12703
- const providerName = options.provider ?? resolveDefaultDecisionProvider();
12705
+ // SDK config counts as much as the environment: credentials given to the
12706
+ // constructor or to this call can configure a provider on their own.
12707
+ const providerName = options.provider ??
12708
+ resolveDefaultDecisionProvider(this.resolveCredentials(options.credentials));
12704
12709
  if (!providerName) {
12705
- throw new Error("No decision provider is configured. Set TYPESAFE_API_KEY, or pass `provider` explicitly.");
12710
+ throw new Error(`No decision provider is configured. Set ${describeDecisionProviderKeys()} (in the environment or in \`credentials\`), or pass \`provider\` explicitly.`);
12706
12711
  }
12707
12712
  const questionCount = Object.keys(options.questions).length;
12708
12713
  // Observability parity with generate()/stream(): an OTEL span for the
@@ -18,7 +18,7 @@ import { logger } from "../../utils/logger.js";
18
18
  import { drainDetachedPump } from "../../utils/drainDetachedPump.js";
19
19
  import { ANTHROPIC_ELISION_NOTE, planAnthropicLoopReclaim, previewAnthropicToolResultText, } from "../../context/anthropicLoopGuard.js";
20
20
  import { getAvailableInputTokens } from "../../constants/contextWindows.js";
21
- import { estimateTokens } from "../../utils/tokenEstimation.js";
21
+ import { estimateTokens, serializeForEstimate, } from "../../utils/tokenEstimation.js";
22
22
  import { redactUrlCredentials } from "../../utils/logSanitize.js";
23
23
  import { ANTHROPIC_MAX_CACHE_BREAKPOINTS, applyAnthropicHistoryCacheBreakpoints, countAnthropicCacheMarkers, } from "../../utils/anthropicCacheBreakpoints.js";
24
24
  import { calculateCost } from "../../utils/pricing.js";
@@ -47,6 +47,7 @@ import { createStreamChannel } from "../../core/streamChannel.js";
47
47
  import { toNativeToolDeclarations } from "../../core/nativeToolFormat.js";
48
48
  import { ANTHROPIC_BETA_HEADERS } from "./constants.js";
49
49
  import { cacheControlOf, withLastToolCacheBreakpoint } from "./cacheControl.js";
50
+ import { createNativeGenerateGuard } from "../../context/nativeGenerateGuard.js";
50
51
  import { appendFinalResultInstruction, appendFinalResultTool, FINAL_RESULT_TOOL_NAME, } from "./structuredOutput.js";
51
52
  // AnthropicProviderConfig is imported from types/providers.ts
52
53
  // Re-export for backward compatibility
@@ -1527,6 +1528,21 @@ export class AnthropicProvider extends BaseProvider {
1527
1528
  const toolExecutionSummaries = [];
1528
1529
  const loop = await runNativeGenerateLoop({
1529
1530
  doGenerate,
1531
+ ...createNativeGenerateGuard({
1532
+ provider: "anthropic",
1533
+ availableInputTokens: getAvailableInputTokens("anthropic", modelId, options.maxTokens ?? undefined),
1534
+ // Runs on every step of the generate loop, so a cyclic or
1535
+ // oversized tool schema must not throw the turn away. Shares the
1536
+ // estimator's own serializer, matching the OpenAI-compatible
1537
+ // native guard's wiring: its fallback over-reports, which makes
1538
+ // the guard fire rather than silently size the overhead at
1539
+ // nothing.
1540
+ getFixedOverheadTokens: () => estimateTokens(serializeForEstimate({
1541
+ tools: v3Tools,
1542
+ responseFormat,
1543
+ providerOptions,
1544
+ }), "anthropic"),
1545
+ }),
1530
1546
  conversation,
1531
1547
  ...(hasTools ? { tools: v3Tools } : {}),
1532
1548
  toolsRecord,
@@ -0,0 +1,40 @@
1
+ import type { DecisionError, DecisionState, NeurolinkCredentials } from "../types/index.js";
2
+ import { SystemOneDecisionProvider } from "./systemOneDecision.js";
3
+ /**
4
+ * Laya Provider — the `decide` inference type only.
5
+ *
6
+ * Laya is Convai Innovations' open-weights "System One" decision model: the
7
+ * same typed `noul` / `choice` / `score` questions as TypeSafe's Jev, answered
8
+ * by an encoder in one forward pass, on the same wire. The request loop,
9
+ * retries, auth circuit breaker and answer parsing are shared with every
10
+ * decision provider in {@link SystemOneDecisionProvider}.
11
+ *
12
+ * Its encoders read far less than Jev: 1,024 tokens on the `typed-decisions`
13
+ * and `multilingual` checkpoints, 512 on `english`. The descriptor's
14
+ * `decisionLimits` refuses what does not fit rather than letting the server
15
+ * cut the state off silently.
16
+ *
17
+ * @see https://github.com/NandhaKishorM/laya
18
+ */
19
+ export declare class LayaProvider extends SystemOneDecisionProvider {
20
+ private readonly apiKey;
21
+ private readonly baseURL;
22
+ constructor(modelName?: string, sdk?: unknown, _region?: string, credentials?: NeurolinkCredentials["laya"]);
23
+ protected getDefaultModel(): string;
24
+ protected vendorLabel(): string;
25
+ protected vendorDisplayName(): string;
26
+ protected decisionApiKey(): string;
27
+ protected missingKeyMessage(): string;
28
+ protected missingConfigMessage(): string | undefined;
29
+ protected decisionEndpoint(): string;
30
+ protected decisionHeaders(): Record<string, string>;
31
+ /** `auto` means "let Laya's router choose", which it does when no model is named. */
32
+ protected buildDecisionBody(state: DecisionState, questions: Record<string, Record<string, unknown>>, model: string): Record<string, unknown>;
33
+ protected parseDecisionError(status: number, payload: unknown, requestId: string | undefined): DecisionError;
34
+ protected readRequestId(headers: Headers): string | undefined;
35
+ /**
36
+ * The checkpoint that actually answered is `routing.model` — the one Laya's
37
+ * router picked when the request said `auto`.
38
+ */
39
+ protected resolveResponseModel(payload: Record<string, unknown>, requestedModel: string): string;
40
+ }