@juspay/neurolink 12.56.0 → 12.57.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 +2 -2
- package/README.md +65 -54
- package/dist/browser/neurolink.min.js +409 -409
- package/dist/cli/commands/setup.d.ts +1 -1
- package/dist/cli/commands/setup.js +1 -1
- package/dist/cli/factories/commandFactory.js +1 -1
- package/dist/constants/enums.d.ts +4 -0
- package/dist/constants/enums.js +5 -0
- package/dist/factories/providerDescriptors.js +12 -7
- package/dist/neurolink.d.ts +12 -8
- package/dist/neurolink.js +89 -25
- package/dist/providers/catalog/index.generated.d.ts +1 -1
- package/dist/providers/catalog/index.generated.js +3 -1
- package/dist/providers/catalog/subq.json +59 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/ollamaDiagnostics.d.ts +31 -0
- package/dist/types/ollamaDiagnostics.js +1 -0
- package/dist/types/providerCatalog.generated.d.ts +2 -2
- package/dist/types/providers.d.ts +4 -0
- package/dist/utils/ollamaDiagnostics.d.ts +69 -0
- package/dist/utils/ollamaDiagnostics.js +192 -0
- package/dist/utils/providerHealth.d.ts +33 -19
- package/dist/utils/providerHealth.js +224 -85
- package/docs-site/static/search-index.json +62 -46
- package/package.json +3 -1
|
@@ -13,7 +13,7 @@ import type { ProviderConfigOptions, SetupArgs } from "../../types/index.js";
|
|
|
13
13
|
* perplexity, sambanova, together-ai, xai — mistral is the 9th catalog
|
|
14
14
|
* provider but keeps its own handleMistralSetup() flow above, so it's
|
|
15
15
|
* excluded here), spread directly from the catalog JSON via
|
|
16
|
-
* buildCatalogConfigOptions(); decide-kind catalog entries (laya, xor) are
|
|
16
|
+
* buildCatalogConfigOptions(); decide-kind catalog entries (laya, xor, subq) are
|
|
17
17
|
* spread the same way from getDecideCatalogEntries(). The hand rows listed
|
|
18
18
|
* first reuse the existing createXConfig() factories in providerConfig.ts; the
|
|
19
19
|
* remaining 5 (ollama, litellm, sagemaker, lm-studio, llamacpp) don't have a
|
|
@@ -150,7 +150,7 @@ const PROVIDERS = [
|
|
|
150
150
|
* perplexity, sambanova, together-ai, xai — mistral is the 9th catalog
|
|
151
151
|
* provider but keeps its own handleMistralSetup() flow above, so it's
|
|
152
152
|
* excluded here), spread directly from the catalog JSON via
|
|
153
|
-
* buildCatalogConfigOptions(); decide-kind catalog entries (laya, xor) are
|
|
153
|
+
* buildCatalogConfigOptions(); decide-kind catalog entries (laya, xor, subq) are
|
|
154
154
|
* spread the same way from getDecideCatalogEntries(). The hand rows listed
|
|
155
155
|
* first reuse the existing createXConfig() factories in providerConfig.ts; the
|
|
156
156
|
* remaining 5 (ollama, litellm, sagemaker, lm-studio, llamacpp) don't have a
|
|
@@ -649,7 +649,7 @@ export class CLICommandFactory {
|
|
|
649
649
|
},
|
|
650
650
|
classifierStrategy: {
|
|
651
651
|
type: "string",
|
|
652
|
-
description: "Classifier strategy: 'auto' (default — 'jev' when a decision provider is configured, such as TYPESAFE_API_KEY, LAYA_API_KEY with LAYA_BASE_URL, XOR_API_KEY with XOR_BASE_URL, PERPLEXITY_API_KEY, or CLOUDFLARE_API_KEY with CLOUDFLARE_ACCOUNT_ID, else 'heuristic'), 'heuristic' (no LLM), 'llm' (a cheap model picks per prompt), or 'jev' (a System One decision model — TypeSafe Jev, Laya, XOR, Perplexity or Cloudflare Clef — with calibrated confidence).",
|
|
652
|
+
description: "Classifier strategy: 'auto' (default — 'jev' when a decision provider is configured, such as TYPESAFE_API_KEY, LAYA_API_KEY with LAYA_BASE_URL, XOR_API_KEY with XOR_BASE_URL, SUBQ_API_KEY, PERPLEXITY_API_KEY, or CLOUDFLARE_API_KEY with CLOUDFLARE_ACCOUNT_ID, else 'heuristic'), 'heuristic' (no LLM), 'llm' (a cheap model picks per prompt), or 'jev' (a System One decision model — TypeSafe Jev, Laya, XOR, SubQ, Perplexity or Cloudflare Clef — with calibrated confidence).",
|
|
653
653
|
choices: ["auto", "heuristic", "llm", "jev"],
|
|
654
654
|
alias: "classifier-strategy",
|
|
655
655
|
},
|
|
@@ -89,6 +89,7 @@ export declare enum AIProviderName {
|
|
|
89
89
|
STACKIT = "stackit",
|
|
90
90
|
STEPFUN = "stepfun",
|
|
91
91
|
SUBCONSCIOUS = "subconscious",
|
|
92
|
+
SUBQ = "subq",
|
|
92
93
|
SYNTHETIC = "synthetic",
|
|
93
94
|
TELNYX = "telnyx",
|
|
94
95
|
THINKING_MACHINES = "thinking-machines",
|
|
@@ -1611,6 +1612,9 @@ export declare enum SubconsciousModels {
|
|
|
1611
1612
|
SUBCONSCIOUS_DEEPSEEK_V4_1_FLASH_MARATHON = "subconscious/deepseek-v4.1-flash-marathon",
|
|
1612
1613
|
SUBCONSCIOUS_TIM_QWEN3_6_27B = "subconscious/tim-qwen3.6-27b"
|
|
1613
1614
|
}
|
|
1615
|
+
export declare enum SubqModels {
|
|
1616
|
+
SUBQ_SNAP_PREVIEW = "subq-snap-preview"
|
|
1617
|
+
}
|
|
1614
1618
|
export declare enum SyntheticModels {
|
|
1615
1619
|
SYN_LARGE_TEXT = "syn:large:text",
|
|
1616
1620
|
SYN_SMALL_TEXT = "syn:small:text",
|
package/dist/constants/enums.js
CHANGED
|
@@ -94,6 +94,7 @@ export var AIProviderName;
|
|
|
94
94
|
AIProviderName["STACKIT"] = "stackit";
|
|
95
95
|
AIProviderName["STEPFUN"] = "stepfun";
|
|
96
96
|
AIProviderName["SUBCONSCIOUS"] = "subconscious";
|
|
97
|
+
AIProviderName["SUBQ"] = "subq";
|
|
97
98
|
AIProviderName["SYNTHETIC"] = "synthetic";
|
|
98
99
|
AIProviderName["TELNYX"] = "telnyx";
|
|
99
100
|
AIProviderName["THINKING_MACHINES"] = "thinking-machines";
|
|
@@ -1920,6 +1921,10 @@ export var SubconsciousModels;
|
|
|
1920
1921
|
SubconsciousModels["SUBCONSCIOUS_DEEPSEEK_V4_1_FLASH_MARATHON"] = "subconscious/deepseek-v4.1-flash-marathon";
|
|
1921
1922
|
SubconsciousModels["SUBCONSCIOUS_TIM_QWEN3_6_27B"] = "subconscious/tim-qwen3.6-27b";
|
|
1922
1923
|
})(SubconsciousModels || (SubconsciousModels = {}));
|
|
1924
|
+
export var SubqModels;
|
|
1925
|
+
(function (SubqModels) {
|
|
1926
|
+
SubqModels["SUBQ_SNAP_PREVIEW"] = "subq-snap-preview";
|
|
1927
|
+
})(SubqModels || (SubqModels = {}));
|
|
1923
1928
|
export var SyntheticModels;
|
|
1924
1929
|
(function (SyntheticModels) {
|
|
1925
1930
|
SyntheticModels["SYN_LARGE_TEXT"] = "syn:large:text";
|
|
@@ -468,22 +468,27 @@ const HAND_DESCRIPTORS = [
|
|
|
468
468
|
setupUrl: "https://console.typesafe.ai/keys",
|
|
469
469
|
},
|
|
470
470
|
// Decision precedence is decideOrder, not position: typesafe 1, laya 2 and
|
|
471
|
-
// xor 3 (from catalog/laya.json and catalog/xor.json),
|
|
472
|
-
// cloudflare-clef
|
|
471
|
+
// xor 3 (from catalog/laya.json and catalog/xor.json), subq 4 (from
|
|
472
|
+
// catalog/subq.json), perplexity-decider 5, cloudflare-clef 6.
|
|
473
473
|
// resolveDefaultDecisionProvider() returns the first configured
|
|
474
474
|
// DECISION_PROVIDERS entry in that order, so a host configured for several
|
|
475
475
|
// keeps Jev for every built-in consumer and reaches the others only by
|
|
476
476
|
// naming them. Renumbering silently changes which model routes, compacts
|
|
477
477
|
// and plans for every such host.
|
|
478
|
+
// perplexity-decider and cloudflare-clef come last because each shares its
|
|
479
|
+
// environment key with a text provider: a key set only for that text provider
|
|
480
|
+
// must not displace a decision provider a host set up on purpose. subq is
|
|
481
|
+
// ahead of them only because SUBQ_API_KEY belongs to no other provider.
|
|
478
482
|
{
|
|
479
483
|
name: AIProviderName.PERPLEXITY_DECIDER,
|
|
480
484
|
aliases: [],
|
|
481
485
|
credentialsKey: "perplexityDecider",
|
|
482
486
|
envVars: {
|
|
483
487
|
// The same key the `perplexity` text provider reads, so an ambient
|
|
484
|
-
// PERPLEXITY_API_KEY configures this provider too. Its decideOrder (
|
|
485
|
-
// sits after XOR's (3), which
|
|
486
|
-
// decision provider a host
|
|
488
|
+
// PERPLEXITY_API_KEY configures this provider too. Its decideOrder (5)
|
|
489
|
+
// sits after XOR's (3) and SubQ's (4), which have keys of their own, which
|
|
490
|
+
// is what keeps that from displacing any other decision provider a host
|
|
491
|
+
// has configured.
|
|
487
492
|
apiKey: "PERPLEXITY_API_KEY",
|
|
488
493
|
// Optional: the API is hosted at a public endpoint, so a key alone is
|
|
489
494
|
// enough and there is no extraRequired.
|
|
@@ -495,7 +500,7 @@ const HAND_DESCRIPTORS = [
|
|
|
495
500
|
// declaration that keeps it out of every generation code path, and out of
|
|
496
501
|
// the way of the `perplexity` text provider.
|
|
497
502
|
inferenceKinds: ["decide"],
|
|
498
|
-
decideOrder:
|
|
503
|
+
decideOrder: 5,
|
|
499
504
|
toolSupport: "none",
|
|
500
505
|
localRuntime: false,
|
|
501
506
|
healthCheck: "env-only",
|
|
@@ -563,7 +568,7 @@ const HAND_DESCRIPTORS = [
|
|
|
563
568
|
// declaration that keeps it out of every generation code path, and out of
|
|
564
569
|
// the way of the `cloudflare` text provider.
|
|
565
570
|
inferenceKinds: ["decide"],
|
|
566
|
-
decideOrder:
|
|
571
|
+
decideOrder: 6,
|
|
567
572
|
toolSupport: "none",
|
|
568
573
|
localRuntime: false,
|
|
569
574
|
healthCheck: "env-only",
|
package/dist/neurolink.d.ts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NeuroLink - Unified AI Interface with Real MCP Tool Integration
|
|
3
|
-
*
|
|
4
|
-
* REDESIGNED FALLBACK CHAIN - NO CIRCULAR DEPENDENCIES
|
|
5
|
-
* Enhanced AI provider system with natural MCP tool access.
|
|
6
|
-
* Uses real MCP infrastructure for tool discovery and execution.
|
|
7
|
-
*/
|
|
8
1
|
import type { DecisionCallerOptions, DecisionLimitsQuery, DecisionLimitsReading, DecisionOptions, DecisionResult, AgentDefinition, AgentNetworkConfig, AgentRunOptions, AgentRunOutcome, AgentToolRegistrationOptions, IsolatedAgentDefinition, NetworkExecutionInput, NetworkExecutionOptions, NetworkExecutionResult, NetworkStreamChunk, WorkerInstanceOptions } from "./types/index.js";
|
|
9
2
|
import type { CompactionConfig, CompactionResult, ArtifactStore, SpanData, ObservabilityConfig, MetricsSummary, MCPToolAnnotations, TraceView, AuthenticatedContext, AuthProvider, JsonObject, NeuroLinkEvents, TypedEventEmitter, MCPEnhancementsConfig, NeuroLinkAuthConfig, NeurolinkConstructorConfig, ChatMessage, ConversationSeedMessage, ConversationSeedOptions, RecordConversationTurnOptions, RecordConversationTurnResult, ExternalMCPOperationResult, ExternalMCPServerInstance, ExternalMCPServerHealth, ExternalMCPToolInfo, GenerateOptions, GenerateResult, ProviderStatus, TextGenerationOptions, TextGenerationResult, MCPExecutableTool, MCPServerInfo, MCPStatus, StreamOptions, StreamResult, ToolExecutionContext, ToolExecutionSummary, ToolInfo, ToolRegistrationOptions, BatchOperationResult, StreamGenerationEndContext, ToolRoutingServerDescriptor, ToolDedupConfig, ToolConfig, KnowledgeEngineStatus, ChecklistState, ArtifactPageRequest, BankArtifactOptions, BankedArtifactRef, DelegateCollectRequest, DelegateCollectResult, DelegateHandle, DelegateRegistrationOptions, DelegateSpawnOptions, BackgroundCommandHandle, BackgroundCommandOptions, BackgroundCommandOutputPage, BackgroundCommandPageRequest, BackgroundCommandPolicy, BackgroundCommandStatus, GitToolResult, GitToolsetOptions } from "./types/index.js";
|
|
10
3
|
import { ConversationMemoryManager } from "./core/conversationMemoryManager.js";
|
|
@@ -612,6 +605,12 @@ export declare class NeuroLink {
|
|
|
612
605
|
* @returns Modified options with orchestrated provider marked in context, or empty object if validation fails
|
|
613
606
|
*/
|
|
614
607
|
private applyStreamOrchestration;
|
|
608
|
+
/**
|
|
609
|
+
* Read a nonempty orchestration preference only when provider is absent/auto.
|
|
610
|
+
* An explicit provider always takes precedence over incoming or generated
|
|
611
|
+
* context; empty, non-string and auto preferences are ignored.
|
|
612
|
+
*/
|
|
613
|
+
private getOrchestratedPreferredProvider;
|
|
615
614
|
/**
|
|
616
615
|
* MAIN ENTRY POINT: Enhanced generate method with new function signature
|
|
617
616
|
* Replaces both generateText and legacy methods
|
|
@@ -937,6 +936,7 @@ export declare class NeuroLink {
|
|
|
937
936
|
*
|
|
938
937
|
* The router is skipped when:
|
|
939
938
|
* - no `requestRouter` is configured on this instance, or
|
|
939
|
+
* - a valid orchestration preference already owns the provider/model pair, or
|
|
940
940
|
* - the caller explicitly set both `options.provider` AND `options.model`
|
|
941
941
|
* (we only skip the router if BOTH are set; a caller setting only one
|
|
942
942
|
* still lets the router fill in the other field).
|
|
@@ -1118,6 +1118,8 @@ export declare class NeuroLink {
|
|
|
1118
1118
|
private generateWithMCPProvider;
|
|
1119
1119
|
/**
|
|
1120
1120
|
* Direct provider generation (no MCP, no recursion)
|
|
1121
|
+
* An explicit provider precedes orchestration context; otherwise a valid
|
|
1122
|
+
* orchestration preference is tried before the existing provider fallback list.
|
|
1121
1123
|
*/
|
|
1122
1124
|
private directProviderGeneration;
|
|
1123
1125
|
/**
|
|
@@ -1324,7 +1326,9 @@ export declare class NeuroLink {
|
|
|
1324
1326
|
*/
|
|
1325
1327
|
private emitStreamStartEvents;
|
|
1326
1328
|
/**
|
|
1327
|
-
* Create MCP stream
|
|
1329
|
+
* Create the provider-backed MCP stream with the existing tool lifecycle.
|
|
1330
|
+
* An explicit provider precedes a valid orchestration context preference;
|
|
1331
|
+
* absent either, getBestProvider retains its normal automatic selection.
|
|
1328
1332
|
*/
|
|
1329
1333
|
private createMCPStream;
|
|
1330
1334
|
/**
|
package/dist/neurolink.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { beginOllamaDiagnostic, captureOllamaDiagnosticContext, completeOllamaDiagnostic, getOllamaDiagnosticErrorMessage, } from "./utils/ollamaDiagnostics.js";
|
|
1
2
|
/**
|
|
2
3
|
* NeuroLink - Unified AI Interface with Real MCP Tool Integration
|
|
3
4
|
*
|
|
@@ -203,13 +204,6 @@ const isNonRetryableForPool = sharedIsNonRetryableForPool;
|
|
|
203
204
|
*/
|
|
204
205
|
const MEMORY_WRITE_TIMEOUT_MS = 30_000;
|
|
205
206
|
/** Native tags share the health check's endpoint precedence and origin. */
|
|
206
|
-
function getOllamaTagsUrl() {
|
|
207
|
-
const baseUrl = process.env.OLLAMA_BASE_URL ||
|
|
208
|
-
process.env.OLLAMA_API_BASE ||
|
|
209
|
-
"http://localhost:11434";
|
|
210
|
-
// Native /api/tags is at the origin even if the compatible base ends /v1.
|
|
211
|
-
return new URL("/api/tags", baseUrl).toString();
|
|
212
|
-
}
|
|
213
207
|
/**
|
|
214
208
|
* NeuroLink - Universal AI Development Platform
|
|
215
209
|
*
|
|
@@ -2737,8 +2731,17 @@ Current user's request: ${currentInput}`;
|
|
|
2737
2731
|
}
|
|
2738
2732
|
// For Ollama, check if service is running and model is available
|
|
2739
2733
|
if (route.provider === "ollama") {
|
|
2734
|
+
let ollamaAttempt;
|
|
2735
|
+
let ollamaOutcome = "not-run";
|
|
2740
2736
|
try {
|
|
2741
|
-
const
|
|
2737
|
+
const ollamaContext = captureOllamaDiagnosticContext();
|
|
2738
|
+
const gate = beginOllamaDiagnostic(ollamaContext);
|
|
2739
|
+
if (gate.kind === "suppressed") {
|
|
2740
|
+
return {};
|
|
2741
|
+
}
|
|
2742
|
+
ollamaAttempt = gate;
|
|
2743
|
+
ollamaOutcome = "transport-failure";
|
|
2744
|
+
const response = await fetch(ollamaContext.url, {
|
|
2742
2745
|
method: "GET",
|
|
2743
2746
|
signal: AbortSignal.timeout(2000),
|
|
2744
2747
|
});
|
|
@@ -2752,6 +2755,7 @@ Current user's request: ${currentInput}`;
|
|
|
2752
2755
|
});
|
|
2753
2756
|
return {}; // Return empty object to preserve existing fallback behavior
|
|
2754
2757
|
}
|
|
2758
|
+
ollamaOutcome = "protocol-failure";
|
|
2755
2759
|
const responseData = await response.json();
|
|
2756
2760
|
const models = responseData?.models;
|
|
2757
2761
|
// Runtime-safe guard: ensure models is an array with valid objects
|
|
@@ -2762,6 +2766,7 @@ Current user's request: ${currentInput}`;
|
|
|
2762
2766
|
});
|
|
2763
2767
|
return {}; // Return empty object for fallback behavior
|
|
2764
2768
|
}
|
|
2769
|
+
ollamaOutcome = "success";
|
|
2765
2770
|
// Filter and validate models before comparison
|
|
2766
2771
|
const validModels = models.filter((m) => m && typeof m === "object" && typeof m.name === "string");
|
|
2767
2772
|
const targetModel = route.model;
|
|
@@ -2807,12 +2812,17 @@ Current user's request: ${currentInput}`;
|
|
|
2807
2812
|
routedProvider: route.provider,
|
|
2808
2813
|
routedModel: route.model,
|
|
2809
2814
|
reason: error instanceof Error
|
|
2810
|
-
? error
|
|
2815
|
+
? getOllamaDiagnosticErrorMessage(error)
|
|
2811
2816
|
: "Ollama service check failed",
|
|
2812
2817
|
orchestrationTime: `${Date.now() - startTime}ms`,
|
|
2813
2818
|
});
|
|
2814
2819
|
return {}; // Return empty object to preserve existing fallback behavior
|
|
2815
2820
|
}
|
|
2821
|
+
finally {
|
|
2822
|
+
if (ollamaAttempt) {
|
|
2823
|
+
completeOllamaDiagnostic(ollamaAttempt, ollamaOutcome);
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2816
2826
|
}
|
|
2817
2827
|
logger.debug("Orchestration route determined", {
|
|
2818
2828
|
taskType: classification.type,
|
|
@@ -2875,8 +2885,17 @@ Current user's request: ${currentInput}`;
|
|
|
2875
2885
|
}
|
|
2876
2886
|
// For Ollama, check if service is running and model is available
|
|
2877
2887
|
if (route.provider === "ollama") {
|
|
2888
|
+
let ollamaAttempt;
|
|
2889
|
+
let ollamaOutcome = "not-run";
|
|
2878
2890
|
try {
|
|
2879
|
-
const
|
|
2891
|
+
const ollamaContext = captureOllamaDiagnosticContext();
|
|
2892
|
+
const gate = beginOllamaDiagnostic(ollamaContext);
|
|
2893
|
+
if (gate.kind === "suppressed") {
|
|
2894
|
+
return {};
|
|
2895
|
+
}
|
|
2896
|
+
ollamaAttempt = gate;
|
|
2897
|
+
ollamaOutcome = "transport-failure";
|
|
2898
|
+
const response = await fetch(ollamaContext.url, {
|
|
2880
2899
|
method: "GET",
|
|
2881
2900
|
signal: AbortSignal.timeout(2000),
|
|
2882
2901
|
});
|
|
@@ -2890,6 +2909,7 @@ Current user's request: ${currentInput}`;
|
|
|
2890
2909
|
});
|
|
2891
2910
|
return {}; // Return empty object to preserve existing fallback behavior
|
|
2892
2911
|
}
|
|
2912
|
+
ollamaOutcome = "protocol-failure";
|
|
2893
2913
|
const responseData = await response.json();
|
|
2894
2914
|
const models = responseData?.models;
|
|
2895
2915
|
// Runtime-safe guard: ensure models is an array with valid objects
|
|
@@ -2900,6 +2920,7 @@ Current user's request: ${currentInput}`;
|
|
|
2900
2920
|
});
|
|
2901
2921
|
return {}; // Return empty object for fallback behavior
|
|
2902
2922
|
}
|
|
2923
|
+
ollamaOutcome = "success";
|
|
2903
2924
|
// Filter and validate models before comparison
|
|
2904
2925
|
const validModels = models.filter((m) => m && typeof m === "object" && typeof m.name === "string");
|
|
2905
2926
|
const targetModel = route.model;
|
|
@@ -2945,12 +2966,17 @@ Current user's request: ${currentInput}`;
|
|
|
2945
2966
|
routedProvider: route.provider,
|
|
2946
2967
|
routedModel: route.model,
|
|
2947
2968
|
reason: error instanceof Error
|
|
2948
|
-
? error
|
|
2969
|
+
? getOllamaDiagnosticErrorMessage(error)
|
|
2949
2970
|
: "Ollama service check failed",
|
|
2950
2971
|
orchestrationTime: `${Date.now() - startTime}ms`,
|
|
2951
2972
|
});
|
|
2952
2973
|
return {}; // Return empty object to preserve existing fallback behavior
|
|
2953
2974
|
}
|
|
2975
|
+
finally {
|
|
2976
|
+
if (ollamaAttempt) {
|
|
2977
|
+
completeOllamaDiagnostic(ollamaAttempt, ollamaOutcome);
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2954
2980
|
}
|
|
2955
2981
|
logger.debug("Stream orchestration route determined", {
|
|
2956
2982
|
taskType: classification.type,
|
|
@@ -2978,6 +3004,22 @@ Current user's request: ${currentInput}`;
|
|
|
2978
3004
|
throw error;
|
|
2979
3005
|
}
|
|
2980
3006
|
}
|
|
3007
|
+
/**
|
|
3008
|
+
* Read a nonempty orchestration preference only when provider is absent/auto.
|
|
3009
|
+
* An explicit provider always takes precedence over incoming or generated
|
|
3010
|
+
* context; empty, non-string and auto preferences are ignored.
|
|
3011
|
+
*/
|
|
3012
|
+
getOrchestratedPreferredProvider(options) {
|
|
3013
|
+
if (options.provider && options.provider !== "auto") {
|
|
3014
|
+
return undefined;
|
|
3015
|
+
}
|
|
3016
|
+
const preferred = options.context?.__orchestratedPreferredProvider;
|
|
3017
|
+
return typeof preferred === "string" &&
|
|
3018
|
+
preferred.length > 0 &&
|
|
3019
|
+
preferred !== "auto"
|
|
3020
|
+
? preferred
|
|
3021
|
+
: undefined;
|
|
3022
|
+
}
|
|
2981
3023
|
/**
|
|
2982
3024
|
* MAIN ENTRY POINT: Enhanced generate method with new function signature
|
|
2983
3025
|
* Replaces both generateText and legacy methods
|
|
@@ -4339,6 +4381,7 @@ Current user's request: ${currentInput}`;
|
|
|
4339
4381
|
*
|
|
4340
4382
|
* The router is skipped when:
|
|
4341
4383
|
* - no `requestRouter` is configured on this instance, or
|
|
4384
|
+
* - a valid orchestration preference already owns the provider/model pair, or
|
|
4342
4385
|
* - the caller explicitly set both `options.provider` AND `options.model`
|
|
4343
4386
|
* (we only skip the router if BOTH are set; a caller setting only one
|
|
4344
4387
|
* still lets the router fill in the other field).
|
|
@@ -4358,8 +4401,11 @@ Current user's request: ${currentInput}`;
|
|
|
4358
4401
|
}
|
|
4359
4402
|
// Stand down if the classifier router already selected a provider/model on
|
|
4360
4403
|
// this turn — one explicit precedence order: classifierRouter wins.
|
|
4361
|
-
if (options.context
|
|
4362
|
-
|
|
4404
|
+
if (options.context?.__classifierRouted) {
|
|
4405
|
+
return;
|
|
4406
|
+
}
|
|
4407
|
+
// Keep an orchestration-selected model with the provider that owns it.
|
|
4408
|
+
if (this.getOrchestratedPreferredProvider(options)) {
|
|
4363
4409
|
return;
|
|
4364
4410
|
}
|
|
4365
4411
|
// Skip if the caller explicitly set both provider AND model — they know
|
|
@@ -6577,6 +6623,8 @@ Current user's request: ${currentInput}`;
|
|
|
6577
6623
|
}
|
|
6578
6624
|
/**
|
|
6579
6625
|
* Direct provider generation (no MCP, no recursion)
|
|
6626
|
+
* An explicit provider precedes orchestration context; otherwise a valid
|
|
6627
|
+
* orchestration preference is tried before the existing provider fallback list.
|
|
6580
6628
|
*/
|
|
6581
6629
|
async directProviderGeneration(options) {
|
|
6582
6630
|
const startTime = Date.now();
|
|
@@ -6593,13 +6641,8 @@ Current user's request: ${currentInput}`;
|
|
|
6593
6641
|
"ollama",
|
|
6594
6642
|
];
|
|
6595
6643
|
const requestedProvider = options.provider === "auto" ? undefined : options.provider;
|
|
6596
|
-
//
|
|
6597
|
-
const preferredOrchestrated = options
|
|
6598
|
-
typeof options.context === "object" &&
|
|
6599
|
-
"__orchestratedPreferredProvider" in options.context
|
|
6600
|
-
? options.context
|
|
6601
|
-
.__orchestratedPreferredProvider
|
|
6602
|
-
: undefined;
|
|
6644
|
+
// Read the shared preference while keeping an explicit provider first.
|
|
6645
|
+
const preferredOrchestrated = this.getOrchestratedPreferredProvider(options);
|
|
6603
6646
|
// Build provider list with orchestrated preference first, then fallback to full list
|
|
6604
6647
|
const tryProviders = preferredOrchestrated
|
|
6605
6648
|
? [
|
|
@@ -9425,11 +9468,16 @@ Current user's request: ${currentInput}`;
|
|
|
9425
9468
|
this.emitter.emit("message", `Starting ${options.provider || "auto"} stream...`);
|
|
9426
9469
|
}
|
|
9427
9470
|
/**
|
|
9428
|
-
* Create MCP stream
|
|
9471
|
+
* Create the provider-backed MCP stream with the existing tool lifecycle.
|
|
9472
|
+
* An explicit provider precedes a valid orchestration context preference;
|
|
9473
|
+
* absent either, getBestProvider retains its normal automatic selection.
|
|
9429
9474
|
*/
|
|
9430
9475
|
async createMCPStream(options) {
|
|
9431
|
-
//
|
|
9432
|
-
const
|
|
9476
|
+
// Consume the validated orchestration choice after an explicit provider.
|
|
9477
|
+
const requestedProvider = options.provider && options.provider !== "auto"
|
|
9478
|
+
? options.provider
|
|
9479
|
+
: this.getOrchestratedPreferredProvider(options);
|
|
9480
|
+
const providerName = await getBestProvider(requestedProvider);
|
|
9433
9481
|
const provider = await AIProviderFactory.createProvider(providerName, options.model, !options.disableTools, // Pass disableTools as inverse of enableMCP
|
|
9434
9482
|
this, // Pass SDK instance
|
|
9435
9483
|
options.region, // Pass region parameter
|
|
@@ -11900,14 +11948,24 @@ Current user's request: ${currentInput}`;
|
|
|
11900
11948
|
}
|
|
11901
11949
|
// Special handling for Ollama
|
|
11902
11950
|
if (providerName === "ollama") {
|
|
11951
|
+
let ollamaAttempt;
|
|
11952
|
+
let ollamaOutcome = "not-run";
|
|
11903
11953
|
try {
|
|
11904
|
-
const
|
|
11954
|
+
const ollamaContext = captureOllamaDiagnosticContext();
|
|
11955
|
+
const gate = beginOllamaDiagnostic(ollamaContext);
|
|
11956
|
+
if (gate.kind === "suppressed") {
|
|
11957
|
+
throw new Error(gate.reason);
|
|
11958
|
+
}
|
|
11959
|
+
ollamaAttempt = gate;
|
|
11960
|
+
ollamaOutcome = "transport-failure";
|
|
11961
|
+
const response = await fetch(ollamaContext.url, {
|
|
11905
11962
|
method: "GET",
|
|
11906
11963
|
signal: AbortSignal.timeout(PROVIDER_TIMEOUTS.AUTH_MS),
|
|
11907
11964
|
});
|
|
11908
11965
|
if (!response.ok) {
|
|
11909
11966
|
throw new Error("Ollama service not responding");
|
|
11910
11967
|
}
|
|
11968
|
+
ollamaOutcome = "protocol-failure";
|
|
11911
11969
|
const responseData = await response.json();
|
|
11912
11970
|
const models = responseData?.models;
|
|
11913
11971
|
// Runtime-safe guard: ensure models is an array with valid objects
|
|
@@ -11918,6 +11976,7 @@ Current user's request: ${currentInput}`;
|
|
|
11918
11976
|
});
|
|
11919
11977
|
throw new Error("Invalid models format from Ollama API");
|
|
11920
11978
|
}
|
|
11979
|
+
ollamaOutcome = "success";
|
|
11921
11980
|
// Filter and validate models before comparison
|
|
11922
11981
|
const validModels = models.filter((m) => m && typeof m === "object" && typeof m.name === "string");
|
|
11923
11982
|
if (validModels.length > 0) {
|
|
@@ -11948,11 +12007,16 @@ Current user's request: ${currentInput}`;
|
|
|
11948
12007
|
configured: false,
|
|
11949
12008
|
authenticated: false,
|
|
11950
12009
|
error: error instanceof Error
|
|
11951
|
-
? error
|
|
12010
|
+
? getOllamaDiagnosticErrorMessage(error)
|
|
11952
12011
|
: "Ollama service not running",
|
|
11953
12012
|
responseTime: Date.now() - startTime,
|
|
11954
12013
|
};
|
|
11955
12014
|
}
|
|
12015
|
+
finally {
|
|
12016
|
+
if (ollamaAttempt) {
|
|
12017
|
+
completeOllamaDiagnostic(ollamaAttempt, ollamaOutcome);
|
|
12018
|
+
}
|
|
12019
|
+
}
|
|
11956
12020
|
}
|
|
11957
12021
|
// Test other providers with actual generation call. The losing
|
|
11958
12022
|
// side of the race is aborted in `finally` below — previously the
|
|
@@ -2,4 +2,4 @@ import type { DecideCatalogJson, ProviderCatalogJson } from "../../types/index.j
|
|
|
2
2
|
export declare const CATALOG_JSON_ENTRIES: ProviderCatalogJson[];
|
|
3
3
|
export declare const CATALOG_PROVIDER_IDS: readonly ["a2agent", "abliteration", "above-dev", "ai21", "aiand", "aihubmix", "aionlabs", "ambient", "api-route", "arcee", "atlas-cloud", "avian-io", "baidu-qianfan", "baseten", "bee-heossi", "byteplus-modelark", "bytez", "cerebras", "charm-hyper", "chutes", "cloudflare", "crusoe", "dashscope", "deepinfra", "deepseek", "empiriolabs", "featherless-ai", "fireworks", "friendli", "gmicloud", "gradientai", "groq", "hetzner-inference", "huggingface", "inception-labs", "inceptron", "inco", "inference-net", "io-intelligence", "koscompute", "lemonfox-ai", "lilac", "llmtech", "longcat", "mancer", "meta-model-api", "minimax", "mistral", "moark", "modelscope", "moonshot-ai", "morph", "naver-clova-studio", "nebius", "neuralwatt", "novita", "ovhcloud", "parasail", "pareto-inference", "perplexity", "poolside", "prime-intellect", "reka", "runinfra", "sakana-ai", "sambanova", "sarvam", "scaleway", "siliconflow", "stackit", "stepfun", "subconscious", "synthetic", "telnyx", "thinking-machines", "tinfoil", "together-ai", "umans-ai", "upstage", "venice-ai", "vispark", "vultr-inference", "wafer", "wandb-inference", "xai", "xiaomi-mimo", "z-ai"];
|
|
4
4
|
export declare const DECIDE_CATALOG_JSON_ENTRIES: DecideCatalogJson[];
|
|
5
|
-
export declare const DECIDE_CATALOG_PROVIDER_IDS: readonly ["laya", "xor"];
|
|
5
|
+
export declare const DECIDE_CATALOG_PROVIDER_IDS: readonly ["laya", "subq", "xor"];
|
|
@@ -73,6 +73,7 @@ import siliconflowJson from "./siliconflow.json" with { type: "json" };
|
|
|
73
73
|
import stackitJson from "./stackit.json" with { type: "json" };
|
|
74
74
|
import stepfunJson from "./stepfun.json" with { type: "json" };
|
|
75
75
|
import subconsciousJson from "./subconscious.json" with { type: "json" };
|
|
76
|
+
import subqJson from "./subq.json" with { type: "json" };
|
|
76
77
|
import syntheticJson from "./synthetic.json" with { type: "json" };
|
|
77
78
|
import telnyxJson from "./telnyx.json" with { type: "json" };
|
|
78
79
|
import thinkingMachinesJson from "./thinking-machines.json" with { type: "json" };
|
|
@@ -277,6 +278,7 @@ export const CATALOG_PROVIDER_IDS = [
|
|
|
277
278
|
];
|
|
278
279
|
export const DECIDE_CATALOG_JSON_ENTRIES = [
|
|
279
280
|
layaJson,
|
|
281
|
+
subqJson,
|
|
280
282
|
xorJson,
|
|
281
283
|
].map(asDecideEntry);
|
|
282
|
-
export const DECIDE_CATALOG_PROVIDER_IDS = ["laya", "xor"];
|
|
284
|
+
export const DECIDE_CATALOG_PROVIDER_IDS = ["laya", "subq", "xor"];
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./provider-catalog.schema.json",
|
|
3
|
+
"id": "subq",
|
|
4
|
+
"displayName": "SubQ",
|
|
5
|
+
"aliases": ["subquadratic", "subq-snap"],
|
|
6
|
+
"inferenceKinds": ["decide"],
|
|
7
|
+
"wire": { "baseURL": "https://api.subq.ai" },
|
|
8
|
+
"models": {
|
|
9
|
+
"default": "subq-snap-preview",
|
|
10
|
+
"topModels": ["subq-snap-preview"],
|
|
11
|
+
"catalog": {
|
|
12
|
+
"subq-snap-preview": {
|
|
13
|
+
"contextWindow": 393216,
|
|
14
|
+
"maxOutputTokens": 1,
|
|
15
|
+
"vision": false,
|
|
16
|
+
"status": "preview",
|
|
17
|
+
"description": "Recommended - SubQ Snap Preview, decision model for boolean, choice and score questions"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"decisionLimits": { "maxStateTokens": 376000, "advisory": true },
|
|
22
|
+
"decide": {
|
|
23
|
+
"dialect": "system-one",
|
|
24
|
+
"order": 4,
|
|
25
|
+
"baseURLNormalize": ["strip-trailing-slash"],
|
|
26
|
+
"endpoint": "{baseURL}/v1/systemone",
|
|
27
|
+
"model": { "placement": "body" },
|
|
28
|
+
"errors": {
|
|
29
|
+
"rules": [
|
|
30
|
+
{ "status": 401, "kind": "authentication" },
|
|
31
|
+
{ "status": [402, 403, 422], "kind": "invalid_request" },
|
|
32
|
+
{ "status": 429, "kind": "rate_limit" },
|
|
33
|
+
{ "status": 503, "kind": "overloaded" },
|
|
34
|
+
{ "statusMin": 500, "kind": "server" }
|
|
35
|
+
],
|
|
36
|
+
"default": "invalid_request",
|
|
37
|
+
"bodyShapes": [{ "path": "detail.message" }, { "path": "detail" }]
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"setup": {
|
|
41
|
+
"url": "https://console.subq.ai",
|
|
42
|
+
"apiKeyFormat": null,
|
|
43
|
+
"billingPolicy": "no-free-tier",
|
|
44
|
+
"description": "API key from the SubQ console",
|
|
45
|
+
"instructions": [
|
|
46
|
+
"1. Sign up at https://console.subq.ai and create an API key (the console shows it once)",
|
|
47
|
+
"2. Set {apiKeyEnvVar} in your .env file",
|
|
48
|
+
"3. A request made with no credits left returns HTTP 402"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"evidence": {
|
|
52
|
+
"rosterVerified": {
|
|
53
|
+
"date": "2026-10-13",
|
|
54
|
+
"method": "Checked by the marketing session, not in this change: GET https://api.subq.ai/v1/models without a key listed subq-snap-preview, and docs.subq.ai/using-the-api/models was read the same day. No request was made to SubQ in this change"
|
|
55
|
+
},
|
|
56
|
+
"liveMatrix": null,
|
|
57
|
+
"addedInPR": "https://github.com/juspay/neurolink/pull/1986"
|
|
58
|
+
}
|
|
59
|
+
}
|
package/dist/types/index.d.ts
CHANGED
package/dist/types/index.js
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Native Ollama diagnostic identity, outcome and captured policy state. */
|
|
2
|
+
export type OllamaDiagnosticContext = Readonly<{
|
|
3
|
+
/** Private resolved URL: never include it, its key, or credentials in logs. */
|
|
4
|
+
url: string;
|
|
5
|
+
key: string;
|
|
6
|
+
model: string;
|
|
7
|
+
}>;
|
|
8
|
+
export type OllamaDiagnosticSnapshot = Readonly<{
|
|
9
|
+
count: number;
|
|
10
|
+
lastFailureAt: number | undefined;
|
|
11
|
+
revision: number;
|
|
12
|
+
generation: number;
|
|
13
|
+
}>;
|
|
14
|
+
export type OllamaDiagnosticState = {
|
|
15
|
+
count: number;
|
|
16
|
+
lastFailureAt: number | undefined;
|
|
17
|
+
revision: number;
|
|
18
|
+
generation: number;
|
|
19
|
+
};
|
|
20
|
+
export type OllamaDiagnosticPermit = Readonly<{
|
|
21
|
+
kind: "allowed";
|
|
22
|
+
context: OllamaDiagnosticContext;
|
|
23
|
+
generation: number;
|
|
24
|
+
}>;
|
|
25
|
+
export type OllamaDiagnosticGate = OllamaDiagnosticPermit | Readonly<{
|
|
26
|
+
kind: "suppressed";
|
|
27
|
+
count: number;
|
|
28
|
+
reason: string;
|
|
29
|
+
generation: number;
|
|
30
|
+
}>;
|
|
31
|
+
export type OllamaDiagnosticOutcome = "success" | "transport-failure" | "protocol-failure" | "not-run";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type CatalogProviderName = "a2agent" | "abliteration" | "above-dev" | "ai21" | "aiand" | "aihubmix" | "aionlabs" | "ambient" | "api-route" | "arcee" | "atlas-cloud" | "avian-io" | "baidu-qianfan" | "baseten" | "bee-heossi" | "byteplus-modelark" | "bytez" | "cerebras" | "charm-hyper" | "chutes" | "cloudflare" | "crusoe" | "dashscope" | "deepinfra" | "deepseek" | "empiriolabs" | "featherless-ai" | "fireworks" | "friendli" | "gmicloud" | "gradientai" | "groq" | "hetzner-inference" | "huggingface" | "inception-labs" | "inceptron" | "inco" | "inference-net" | "io-intelligence" | "koscompute" | "laya" | "lemonfox-ai" | "lilac" | "llmtech" | "longcat" | "mancer" | "meta-model-api" | "minimax" | "mistral" | "moark" | "modelscope" | "moonshot-ai" | "morph" | "naver-clova-studio" | "nebius" | "neuralwatt" | "novita" | "ovhcloud" | "parasail" | "pareto-inference" | "perplexity" | "poolside" | "prime-intellect" | "reka" | "runinfra" | "sakana-ai" | "sambanova" | "sarvam" | "scaleway" | "siliconflow" | "stackit" | "stepfun" | "subconscious" | "synthetic" | "telnyx" | "thinking-machines" | "tinfoil" | "together-ai" | "umans-ai" | "upstage" | "venice-ai" | "vispark" | "vultr-inference" | "wafer" | "wandb-inference" | "xai" | "xiaomi-mimo" | "xor" | "z-ai";
|
|
2
|
-
export type CatalogCredentialKey = "a2agent" | "abliteration" | "aboveDev" | "ai21" | "aiand" | "aihubmix" | "aionlabs" | "ambient" | "apiRoute" | "arcee" | "atlasCloud" | "avianIo" | "baiduQianfan" | "baseten" | "beeHeossi" | "byteplusModelark" | "bytez" | "cerebras" | "charmHyper" | "chutes" | "cloudflare" | "crusoe" | "dashscope" | "deepinfra" | "deepseek" | "empiriolabs" | "featherlessAi" | "fireworks" | "friendli" | "gmicloud" | "gradientai" | "groq" | "hetznerInference" | "huggingFace" | "inceptionLabs" | "inceptron" | "inco" | "inferenceNet" | "ioIntelligence" | "koscompute" | "laya" | "lemonfoxAi" | "lilac" | "llmtech" | "longcat" | "mancer" | "metaModelApi" | "minimax" | "mistral" | "moark" | "modelscope" | "moonshotAi" | "morph" | "naverClovaStudio" | "nebius" | "neuralwatt" | "novita" | "ovhcloud" | "parasail" | "paretoInference" | "perplexity" | "poolside" | "primeIntellect" | "reka" | "runinfra" | "sakanaAi" | "sambanova" | "sarvam" | "scaleway" | "siliconflow" | "stackit" | "stepfun" | "subconscious" | "synthetic" | "telnyx" | "thinkingMachines" | "tinfoil" | "together" | "umansAi" | "upstage" | "veniceAi" | "vispark" | "vultrInference" | "wafer" | "wandbInference" | "xai" | "xiaomiMimo" | "xor" | "zAi";
|
|
1
|
+
export type CatalogProviderName = "a2agent" | "abliteration" | "above-dev" | "ai21" | "aiand" | "aihubmix" | "aionlabs" | "ambient" | "api-route" | "arcee" | "atlas-cloud" | "avian-io" | "baidu-qianfan" | "baseten" | "bee-heossi" | "byteplus-modelark" | "bytez" | "cerebras" | "charm-hyper" | "chutes" | "cloudflare" | "crusoe" | "dashscope" | "deepinfra" | "deepseek" | "empiriolabs" | "featherless-ai" | "fireworks" | "friendli" | "gmicloud" | "gradientai" | "groq" | "hetzner-inference" | "huggingface" | "inception-labs" | "inceptron" | "inco" | "inference-net" | "io-intelligence" | "koscompute" | "laya" | "lemonfox-ai" | "lilac" | "llmtech" | "longcat" | "mancer" | "meta-model-api" | "minimax" | "mistral" | "moark" | "modelscope" | "moonshot-ai" | "morph" | "naver-clova-studio" | "nebius" | "neuralwatt" | "novita" | "ovhcloud" | "parasail" | "pareto-inference" | "perplexity" | "poolside" | "prime-intellect" | "reka" | "runinfra" | "sakana-ai" | "sambanova" | "sarvam" | "scaleway" | "siliconflow" | "stackit" | "stepfun" | "subconscious" | "subq" | "synthetic" | "telnyx" | "thinking-machines" | "tinfoil" | "together-ai" | "umans-ai" | "upstage" | "venice-ai" | "vispark" | "vultr-inference" | "wafer" | "wandb-inference" | "xai" | "xiaomi-mimo" | "xor" | "z-ai";
|
|
2
|
+
export type CatalogCredentialKey = "a2agent" | "abliteration" | "aboveDev" | "ai21" | "aiand" | "aihubmix" | "aionlabs" | "ambient" | "apiRoute" | "arcee" | "atlasCloud" | "avianIo" | "baiduQianfan" | "baseten" | "beeHeossi" | "byteplusModelark" | "bytez" | "cerebras" | "charmHyper" | "chutes" | "cloudflare" | "crusoe" | "dashscope" | "deepinfra" | "deepseek" | "empiriolabs" | "featherlessAi" | "fireworks" | "friendli" | "gmicloud" | "gradientai" | "groq" | "hetznerInference" | "huggingFace" | "inceptionLabs" | "inceptron" | "inco" | "inferenceNet" | "ioIntelligence" | "koscompute" | "laya" | "lemonfoxAi" | "lilac" | "llmtech" | "longcat" | "mancer" | "metaModelApi" | "minimax" | "mistral" | "moark" | "modelscope" | "moonshotAi" | "morph" | "naverClovaStudio" | "nebius" | "neuralwatt" | "novita" | "ovhcloud" | "parasail" | "paretoInference" | "perplexity" | "poolside" | "primeIntellect" | "reka" | "runinfra" | "sakanaAi" | "sambanova" | "sarvam" | "scaleway" | "siliconflow" | "stackit" | "stepfun" | "subconscious" | "subq" | "synthetic" | "telnyx" | "thinkingMachines" | "tinfoil" | "together" | "umansAi" | "upstage" | "veniceAi" | "vispark" | "vultrInference" | "wafer" | "wandbInference" | "xai" | "xiaomiMimo" | "xor" | "zAi";
|