@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.
- package/CHANGELOG.md +3 -3
- package/dist/browser/neurolink.min.js +372 -372
- package/dist/cli/commands/decide.d.ts +2 -1
- package/dist/cli/commands/decide.js +4 -2
- package/dist/cli/commands/setup.js +2 -1
- package/dist/cli/factories/commandFactory.js +1 -1
- package/dist/cli/utils/classifierRouterFlags.js +1 -1
- package/dist/constants/enums.d.ts +15 -0
- package/dist/constants/enums.js +16 -0
- package/dist/core/baseProvider.js +2 -2
- package/dist/factories/providerDescriptors.d.ts +16 -7
- package/dist/factories/providerDescriptors.js +97 -15
- package/dist/factories/providerRegistry.js +9 -1
- package/dist/models/manifestRegistry.js +2 -0
- package/dist/models/manifests/laya.d.ts +12 -0
- package/dist/models/manifests/laya.js +54 -0
- package/dist/neurolink.js +8 -3
- package/dist/providers/anthropic/client.js +17 -1
- package/dist/providers/laya.d.ts +40 -0
- package/dist/providers/laya.js +170 -0
- package/dist/providers/systemOneDecision.d.ts +102 -0
- package/dist/providers/systemOneDecision.js +443 -0
- package/dist/providers/typesafe.d.ts +32 -47
- package/dist/providers/typesafe.js +64 -386
- package/dist/routing/classifierRouter.d.ts +2 -2
- package/dist/routing/classifierRouter.js +10 -8
- package/dist/types/classifierRouter.d.ts +13 -3
- package/dist/types/cli.d.ts +3 -2
- package/dist/types/decision.d.ts +29 -0
- package/dist/types/providers.d.ts +20 -1
- package/dist/utils/modelChoices.js +21 -1
- package/dist/utils/providerConfig.d.ts +5 -0
- package/dist/utils/providerConfig.js +17 -0
- package/docs-site/static/search-index.json +24 -10
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
+
}
|
package/dist/constants/enums.js
CHANGED
|
@@ -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:
|
|
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
|
|
25
|
-
*
|
|
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
|
|
28
|
-
* Returns undefined when none is configured, which every
|
|
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
|
-
*
|
|
558
|
-
*
|
|
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
|
|
561
|
-
* Returns undefined when none is configured, which every
|
|
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
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
+
}
|