@juspay/neurolink 10.3.1 → 10.4.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 (66) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/browser/neurolink.min.js +382 -372
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +3 -0
  5. package/dist/knowledge/context.d.ts +18 -0
  6. package/dist/knowledge/context.js +91 -0
  7. package/dist/knowledge/defaults.d.ts +24 -0
  8. package/dist/knowledge/defaults.js +29 -0
  9. package/dist/knowledge/engine.d.ts +35 -0
  10. package/dist/knowledge/engine.js +179 -0
  11. package/dist/knowledge/index.d.ts +15 -0
  12. package/dist/knowledge/index.js +15 -0
  13. package/dist/knowledge/indexCache.d.ts +19 -0
  14. package/dist/knowledge/indexCache.js +109 -0
  15. package/dist/knowledge/knowledgeIndex.d.ts +41 -0
  16. package/dist/knowledge/knowledgeIndex.js +204 -0
  17. package/dist/knowledge/normalize.d.ts +32 -0
  18. package/dist/knowledge/normalize.js +74 -0
  19. package/dist/knowledge/resolve.d.ts +18 -0
  20. package/dist/knowledge/resolve.js +156 -0
  21. package/dist/knowledge/retrieval.d.ts +16 -0
  22. package/dist/knowledge/retrieval.js +221 -0
  23. package/dist/lib/files/fileTools.d.ts +1 -1
  24. package/dist/lib/index.d.ts +1 -0
  25. package/dist/lib/index.js +3 -0
  26. package/dist/lib/knowledge/context.d.ts +18 -0
  27. package/dist/lib/knowledge/context.js +92 -0
  28. package/dist/lib/knowledge/defaults.d.ts +24 -0
  29. package/dist/lib/knowledge/defaults.js +30 -0
  30. package/dist/lib/knowledge/engine.d.ts +35 -0
  31. package/dist/lib/knowledge/engine.js +180 -0
  32. package/dist/lib/knowledge/index.d.ts +15 -0
  33. package/dist/lib/knowledge/index.js +16 -0
  34. package/dist/lib/knowledge/indexCache.d.ts +19 -0
  35. package/dist/lib/knowledge/indexCache.js +110 -0
  36. package/dist/lib/knowledge/knowledgeIndex.d.ts +41 -0
  37. package/dist/lib/knowledge/knowledgeIndex.js +205 -0
  38. package/dist/lib/knowledge/normalize.d.ts +32 -0
  39. package/dist/lib/knowledge/normalize.js +75 -0
  40. package/dist/lib/knowledge/resolve.d.ts +18 -0
  41. package/dist/lib/knowledge/resolve.js +157 -0
  42. package/dist/lib/knowledge/retrieval.d.ts +16 -0
  43. package/dist/lib/knowledge/retrieval.js +222 -0
  44. package/dist/lib/neurolink.d.ts +14 -1
  45. package/dist/lib/neurolink.js +112 -3
  46. package/dist/lib/types/config.d.ts +12 -0
  47. package/dist/lib/types/conversation.d.ts +1 -1
  48. package/dist/lib/types/dynamic.d.ts +12 -0
  49. package/dist/lib/types/generate.d.ts +14 -0
  50. package/dist/lib/types/index.d.ts +1 -0
  51. package/dist/lib/types/index.js +1 -0
  52. package/dist/lib/types/knowledge.d.ts +342 -0
  53. package/dist/lib/types/knowledge.js +30 -0
  54. package/dist/lib/types/stream.d.ts +14 -0
  55. package/dist/neurolink.d.ts +14 -1
  56. package/dist/neurolink.js +112 -3
  57. package/dist/types/config.d.ts +12 -0
  58. package/dist/types/conversation.d.ts +1 -1
  59. package/dist/types/dynamic.d.ts +12 -0
  60. package/dist/types/generate.d.ts +14 -0
  61. package/dist/types/index.d.ts +1 -0
  62. package/dist/types/index.js +1 -0
  63. package/dist/types/knowledge.d.ts +342 -0
  64. package/dist/types/knowledge.js +29 -0
  65. package/dist/types/stream.d.ts +14 -0
  66. package/package.json +2 -1
@@ -0,0 +1,342 @@
1
+ /**
2
+ * Knowledge grounding — lexical-first host-supplied knowledge retrieval.
3
+ *
4
+ * A host application owns a structured *knowledge registry*: versioned entries
5
+ * describing concepts, configuration, taxonomies, procedures, and operating
6
+ * rules. NeuroLink owns the
7
+ * generic engine that ingests that registry, builds an in-memory lexical
8
+ * index once per instance, and — independently of tool routing — retrieves a
9
+ * small, token-bounded set of relevant entries before each main model call.
10
+ * The selected entries are attached as *ephemeral context*: visible to the
11
+ * current generation call, never persisted into conversation memory.
12
+ *
13
+ * This is retrieval-augmented generation WITHOUT vector retrieval. The first
14
+ * release ranks with exact identifiers, reviewed aliases, metadata filters,
15
+ * and weighted field-aware BM25 only. No embedding model, embedding service,
16
+ * or vector store is initialized. An LLM reranker and semantic retrieval are
17
+ * deferred behind an explicit evaluation gate.
18
+ *
19
+ * Ownership boundary: NeuroLink defines the contracts below and the engine;
20
+ * it never contains host product content. The host supplies content and
21
+ * per-request scope. The engine stays provider-neutral.
22
+ *
23
+ * Type names are globally prefixed `Knowledge*` to satisfy the repo's
24
+ * unique-type-name rule and to avoid collision with the pre-existing
25
+ * web-search `grounding.ts` vocabulary (`EnhancedGroundingMetadata` et al.),
26
+ * which is a different concept (Google search grounding, not product
27
+ * knowledge).
28
+ */
29
+ /** What a knowledge entry primarily is. Drives context labelling, not ranking. */
30
+ export type KnowledgeEntryKind = "concept" | "text" | "configuration" | "tool" | "procedure" | "policy" | "troubleshooting";
31
+ /** Lifecycle state. Only `active` entries are retrievable by default. */
32
+ export type KnowledgeStatus = "draft" | "active" | "deprecated";
33
+ /**
34
+ * Retrieval mode. Only `"lexical"` is supported in the first release; the
35
+ * literal is a union of one to reserve a clean upgrade path to `"hybrid"` /
36
+ * `"vector"` without a breaking change.
37
+ */
38
+ export type KnowledgeRetrievalMode = "lexical";
39
+ /**
40
+ * Confidence class returned with every retrieval so the host prompt can
41
+ * instruct the model to qualify low-confidence answers rather than present
42
+ * them as authoritative.
43
+ */
44
+ export type KnowledgeRetrievalConfidence = "high" | "medium" | "low" | "none";
45
+ /** The five weighted text fields used by the field-aware lexical scorer. */
46
+ export type KnowledgeFieldName = "title" | "aliases" | "keywords" | "summary" | "body";
47
+ /**
48
+ * The record a host author writes. `id`, `title`, `summary`, `domain`, and
49
+ * `integrations` are required; every other field is optional and omitted
50
+ * optionals fall back to SDK defaults during normalization.
51
+ */
52
+ export type KnowledgeEntryInput = {
53
+ /** Stable unique id (e.g. "account.multi-step-flow"). Drives exact-match lookup and citations. */
54
+ id: string;
55
+ /** Human-readable name of the concept/setting. Highest-weighted search field. */
56
+ title: string;
57
+ /** One-line searchable description — the short answer when a full body is unnecessary. */
58
+ summary: string;
59
+ /** Primary grouping and the main retrieval filter (e.g. "account-settings"). */
60
+ domain: string;
61
+ /** Integration identifiers this entry applies to. Empty array = applies to all integrations. */
62
+ integrations: string[];
63
+ /** What the entry is (concept, configuration, procedure, …). Default "text". Labels context, not ranking. */
64
+ kind?: KnowledgeEntryKind;
65
+ /** Lifecycle state. Default "active"; only active entries are retrievable. */
66
+ status?: KnowledgeStatus;
67
+ /** Full explanatory content (Markdown). Use only when the summary is insufficient. */
68
+ body?: string;
69
+ /** Reviewed alternate phrasings or raw identifiers that resolve to exact and alias matches. */
70
+ aliases?: string[];
71
+ /** Extra search terms that aid recall but are not full aliases. */
72
+ keywords?: string[];
73
+ /** Ids of directly related entries, pulled in by bounded relationship expansion. */
74
+ relatedEntryIds?: string[];
75
+ /** Id of the parent entry when this is a subtype or child. */
76
+ parentEntryId?: string;
77
+ };
78
+ /**
79
+ * The complete, defaults-resolved record NeuroLink indexes and injects. Omitted
80
+ * optionals are materialized (arrays to `[]`, `body` to `""`, `kind` to "text",
81
+ * `status` to "active") so downstream code never re-checks the resolution chain.
82
+ * Field meanings mirror `KnowledgeEntryInput`.
83
+ */
84
+ export type NormalizedKnowledgeEntry = {
85
+ id: string;
86
+ title: string;
87
+ summary: string;
88
+ domain: string;
89
+ integrations: string[];
90
+ kind: KnowledgeEntryKind;
91
+ status: KnowledgeStatus;
92
+ body: string;
93
+ aliases: string[];
94
+ keywords: string[];
95
+ relatedEntryIds: string[];
96
+ parentEntryId?: string;
97
+ /** Content version from the source/manifest; appears in citations as [KB:id@version]. */
98
+ version: string;
99
+ };
100
+ /** One catalog inside a build manifest — a source id and its entries. */
101
+ export type KnowledgeManifestCatalog = {
102
+ id: string;
103
+ entries: KnowledgeEntryInput[];
104
+ };
105
+ /**
106
+ * The versioned build artifact a host emits at build time. NeuroLink can
107
+ * consume it directly (each catalog becomes a structured source) so hosts do
108
+ * not need to construct `KnowledgeSource[]` by hand.
109
+ */
110
+ export type KnowledgeManifest = {
111
+ schemaVersion: string;
112
+ contentVersion: string;
113
+ generatedAt: string;
114
+ catalogs: KnowledgeManifestCatalog[];
115
+ };
116
+ /**
117
+ * A configured knowledge source: inline structured entries passed to the
118
+ * engine. Markdown/provider source kinds were intentionally dropped for now;
119
+ * re-introduce this as a discriminated union (with a `type` tag) if another
120
+ * source kind is needed later.
121
+ */
122
+ export type KnowledgeSource = {
123
+ id: string;
124
+ version?: string;
125
+ entries: KnowledgeEntryInput[];
126
+ };
127
+ /**
128
+ * Relative weight applied to a lexical match in each field. Title/alias
129
+ * matches outrank body matches. Tunable through evaluation.
130
+ */
131
+ export type KnowledgeFieldWeights = {
132
+ title: number;
133
+ aliases: number;
134
+ keywords: number;
135
+ summary: number;
136
+ body: number;
137
+ };
138
+ /** Lexical retrieval tuning. All fields optional; the engine supplies defaults. */
139
+ export type KnowledgeRetrievalConfig = {
140
+ /** Retrieval mode. Default: "lexical". */
141
+ mode?: KnowledgeRetrievalMode;
142
+ /** How many scored candidates enter relationship expansion. Default: 24. */
143
+ candidateLimit?: number;
144
+ /** How many primary entries survive into the assembled context. Default: 8. */
145
+ resultLimit?: number;
146
+ /** Cap on relationship-expanded entries added after primary retrieval. Default: 4. */
147
+ relationLimit?: number;
148
+ /** Per-field BM25 weights. */
149
+ fieldWeights?: KnowledgeFieldWeights;
150
+ /** Additive boost for an exact entry-id / configuration-key match. Dominant. Default: 100. */
151
+ exactBoost?: number;
152
+ /** Additive boost for an exact reviewed-alias phrase match. Default: 60. */
153
+ aliasBoost?: number;
154
+ };
155
+ /** Ephemeral-context assembly limits. */
156
+ export type KnowledgeContextConfig = {
157
+ /** Hard token budget for the assembled grounding block. Default: 4000. */
158
+ maxTokens?: number;
159
+ /** Emit `[KB:<id>@<version>]` citations. Default: true. */
160
+ includeCitations?: boolean;
161
+ };
162
+ /**
163
+ * Constructor-level configuration for knowledge grounding. Sources are fixed
164
+ * for the lifetime of a NeuroLink instance so the index can be built once.
165
+ */
166
+ export type KnowledgeGroundingConfig = {
167
+ /** Master switch. Grounding runs only when true AND at least one source is loaded. */
168
+ enabled: boolean;
169
+ /**
170
+ * Knowledge sources used to build the instance's immutable in-memory index.
171
+ * Required alongside `enabled`; pass an empty array only when intentionally
172
+ * configuring no retrievable content.
173
+ */
174
+ sources: KnowledgeSource[];
175
+ /** Exclude these domains from retrieval. Empty/omitted means all domains are eligible. */
176
+ blockedDomains?: string[];
177
+ retrieval?: KnowledgeRetrievalConfig;
178
+ context?: KnowledgeContextConfig;
179
+ /** Hard ceiling for one grounding operation before it fails open. Default: 800ms. */
180
+ timeoutMs?: number;
181
+ };
182
+ /**
183
+ * Per-call scope the host attaches to `GenerateOptions` / `StreamOptions`.
184
+ * Supplies the enabled integrations for this turn only.
185
+ */
186
+ export type KnowledgeRequestScope = {
187
+ /** Installed/enabled integrations used to filter integration-specific entries. */
188
+ enabledIntegrations?: string[];
189
+ };
190
+ /** One bounded recent conversation turn used to contextualize the query. */
191
+ export type KnowledgeConversationTurn = {
192
+ role: "user" | "assistant";
193
+ text: string;
194
+ };
195
+ /**
196
+ * The fully-resolved retrieval request the engine builds internally from the
197
+ * user query, a bounded recent window, and host scope.
198
+ */
199
+ export type KnowledgeRetrievalRequest = {
200
+ query: string;
201
+ recentTurns: KnowledgeConversationTurn[];
202
+ enabledIntegrations: string[];
203
+ };
204
+ /**
205
+ * The internal search document built from a normalized entry. `exactKeys` and
206
+ * `fields` hold pre-tokenized normalized text. Internal to NeuroLink.
207
+ */
208
+ export type IndexedKnowledgeDocument = {
209
+ id: string;
210
+ /** Normalized whole-phrase keys for exact/alias resolution. */
211
+ exactKeys: string[];
212
+ /** Per-field normalized token arrays fed to the field-aware BM25 scorer. */
213
+ fields: {
214
+ title: string[];
215
+ aliases: string[];
216
+ keywords: string[];
217
+ summary: string[];
218
+ body: string[];
219
+ };
220
+ };
221
+ /** One lexical match with its per-field score breakdown, for tuning and traces. */
222
+ export type KnowledgeLexicalMatch = {
223
+ id: string;
224
+ score: number;
225
+ fieldScores: Partial<Record<KnowledgeFieldName, number>>;
226
+ };
227
+ /**
228
+ * Structural contract of the field-aware lexical index held in a snapshot. A
229
+ * concrete class in the knowledge runtime module satisfies this shape; typing
230
+ * it structurally keeps this types file free of runtime imports.
231
+ */
232
+ export type KnowledgeLexicalSearcher = {
233
+ search: (queryTokens: string[], topK: number, eligibleEntryIds?: ReadonlySet<string>) => KnowledgeLexicalMatch[];
234
+ };
235
+ /**
236
+ * Immutable, ready-to-query index built once at client construction. Sessions
237
+ * and turns search this snapshot; it is never mutated in place.
238
+ */
239
+ export type KnowledgeIndexSnapshot = {
240
+ entriesById: Map<string, NormalizedKnowledgeEntry>;
241
+ /** Normalized entry id or title phrase -> entry ids. */
242
+ exactIndex: Map<string, Set<string>>;
243
+ /** Normalized reviewed alias phrase -> entry ids. */
244
+ aliasIndex: Map<string, Set<string>>;
245
+ /** Entry id -> directly related entry ids, for bounded expansion. */
246
+ relationIndex: Map<string, string[]>;
247
+ /** Field-aware BM25 over all documents. */
248
+ lexical: KnowledgeLexicalSearcher;
249
+ entryCount: number;
250
+ };
251
+ /** A stable citation to a specific knowledge entry version. */
252
+ export type KnowledgeCitation = {
253
+ id: string;
254
+ version: string;
255
+ };
256
+ /**
257
+ * The result of one retrieval: the selected entries, the assembled ephemeral
258
+ * context string, a confidence class, and assembly diagnostics.
259
+ */
260
+ export type KnowledgeRetrievalResult = {
261
+ entries: NormalizedKnowledgeEntry[];
262
+ assembledContext: string;
263
+ confidence: KnowledgeRetrievalConfidence;
264
+ citations: KnowledgeCitation[];
265
+ /** Ids of the primary (non-expanded) entries, in final order. */
266
+ selectedEntryIds: string[];
267
+ /** Ids added by bounded relationship expansion. */
268
+ expandedEntryIds: string[];
269
+ /** Candidates scored before truncation to the result limit. */
270
+ candidateCount: number;
271
+ /** Estimated token size of `assembledContext`. */
272
+ contextTokens: number;
273
+ /** True when any entry body was truncated or entries were dropped for budget. */
274
+ truncated: boolean;
275
+ durationMs: number;
276
+ };
277
+ /**
278
+ * A block of context assembled for a single generation call without becoming
279
+ * durable conversation. The NeuroLink call boundary injects its content into
280
+ * the effective system prompt and never persists it as a user message.
281
+ */
282
+ export type EphemeralContext = {
283
+ content: string;
284
+ kind: "knowledge";
285
+ /** Host-supplied reviewed content is trusted reference data. */
286
+ trusted: boolean;
287
+ citations?: KnowledgeCitation[];
288
+ metadata?: Record<string, unknown>;
289
+ };
290
+ /**
291
+ * Aggregate, content-free diagnostics attached to a generation/stream result
292
+ * so the host can evaluate retrieval without the SDK exposing entry bodies.
293
+ */
294
+ export type KnowledgeGroundingMetadata = {
295
+ retrievalMode: KnowledgeRetrievalMode;
296
+ selectedIds: string[];
297
+ expandedIds: string[];
298
+ candidateCount: number;
299
+ contextTokens: number;
300
+ truncated: boolean;
301
+ durationMs: number;
302
+ confidence?: KnowledgeRetrievalConfidence;
303
+ /** Present when grounding failed open; names the failure class. */
304
+ failureReason?: string;
305
+ };
306
+ /** A single validation problem found while normalizing/indexing a source. */
307
+ export type KnowledgeValidationIssue = {
308
+ level: "error" | "warning";
309
+ code: string;
310
+ message: string;
311
+ entryId?: string;
312
+ sourceId?: string;
313
+ };
314
+ /** Outcome of validating a set of sources before indexing. */
315
+ export type KnowledgeValidationResult = {
316
+ ok: boolean;
317
+ issues: KnowledgeValidationIssue[];
318
+ };
319
+ /** Per-turn input to `KnowledgeGroundingEngine.ground()`. */
320
+ export type KnowledgeGroundingInput = {
321
+ query: string;
322
+ recentTurns?: KnowledgeConversationTurn[];
323
+ scope?: KnowledgeRequestScope;
324
+ };
325
+ /**
326
+ * The engine's per-turn output: the ephemeral context to inject (null on
327
+ * no-match, when disabled, or on fail-open), the aggregate metadata for the
328
+ * result, and the full retrieval for host diagnostics.
329
+ */
330
+ export type KnowledgeGroundingOutcome = {
331
+ ephemeralContext: EphemeralContext | null;
332
+ metadata: KnowledgeGroundingMetadata;
333
+ retrieval: KnowledgeRetrievalResult | null;
334
+ };
335
+ /** Snapshot of engine health for telemetry and host introspection. */
336
+ export type KnowledgeEngineStatus = {
337
+ enabled: boolean;
338
+ ready: boolean;
339
+ entryCount: number;
340
+ lastError: string | null;
341
+ validationIssues: KnowledgeValidationIssue[];
342
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Knowledge grounding — lexical-first host-supplied knowledge retrieval.
3
+ *
4
+ * A host application owns a structured *knowledge registry*: versioned entries
5
+ * describing concepts, configuration, taxonomies, procedures, and operating
6
+ * rules. NeuroLink owns the
7
+ * generic engine that ingests that registry, builds an in-memory lexical
8
+ * index once per instance, and — independently of tool routing — retrieves a
9
+ * small, token-bounded set of relevant entries before each main model call.
10
+ * The selected entries are attached as *ephemeral context*: visible to the
11
+ * current generation call, never persisted into conversation memory.
12
+ *
13
+ * This is retrieval-augmented generation WITHOUT vector retrieval. The first
14
+ * release ranks with exact identifiers, reviewed aliases, metadata filters,
15
+ * and weighted field-aware BM25 only. No embedding model, embedding service,
16
+ * or vector store is initialized. An LLM reranker and semantic retrieval are
17
+ * deferred behind an explicit evaluation gate.
18
+ *
19
+ * Ownership boundary: NeuroLink defines the contracts below and the engine;
20
+ * it never contains host product content. The host supplies content and
21
+ * per-request scope. The engine stays provider-neutral.
22
+ *
23
+ * Type names are globally prefixed `Knowledge*` to satisfy the repo's
24
+ * unique-type-name rule and to avoid collision with the pre-existing
25
+ * web-search `grounding.ts` vocabulary (`EnhancedGroundingMetadata` et al.),
26
+ * which is a different concept (Google search grounding, not product
27
+ * knowledge).
28
+ */
29
+ export {};
30
+ //# sourceMappingURL=knowledge.js.map
@@ -1,6 +1,7 @@
1
1
  import type { AIProviderName } from "../constants/enums.js";
2
2
  import type { EvaluationData } from "./evaluation.js";
3
3
  import type { RAGConfig } from "./rag.js";
4
+ import type { KnowledgeGroundingMetadata, KnowledgeRequestScope } from "./knowledge.js";
4
5
  import type { SkillsCallOptions } from "./skills.js";
5
6
  import type { AnalyticsData, ToolExecutionEvent, ToolExecutionSummary } from "../types/index.js";
6
7
  import type { MiddlewareFactoryOptions, OnChunkCallback, OnErrorCallback, OnFinishCallback } from "../types/middleware.js";
@@ -169,6 +170,17 @@ export type StreamChunk = {
169
170
  audio: TTSChunk;
170
171
  };
171
172
  export type StreamOptions = {
173
+ /**
174
+ * Opt this stream call into the knowledge grounding configured on the
175
+ * NeuroLink instance. Defaults to `false` when omitted.
176
+ */
177
+ useKnowledgeGrounding?: boolean;
178
+ /**
179
+ * Enabled integrations used to scope knowledge retrieval for this turn.
180
+ * Used only when `useKnowledgeGrounding` is true and knowledge grounding is
181
+ * enabled on the NeuroLink instance.
182
+ */
183
+ knowledgeContext?: KnowledgeRequestScope;
172
184
  input: {
173
185
  /** Prompt text. Optional for media-only modes (avatar, music) that are driven by uploaded files rather than a prompt. */
174
186
  text?: string;
@@ -552,6 +564,8 @@ export type StreamOptions = {
552
564
  * Future-ready for multi-modal outputs while maintaining text focus
553
565
  */
554
566
  export type StreamResult = {
567
+ /** Knowledge-grounding diagnostics for this turn (present only when grounding ran). */
568
+ knowledge?: KnowledgeGroundingMetadata;
555
569
  stream: AsyncIterable<{
556
570
  content: string;
557
571
  reasoning?: string;
@@ -6,7 +6,7 @@
6
6
  * Uses real MCP infrastructure for tool discovery and execution.
7
7
  */
8
8
  import type { AgentDefinition, AgentNetworkConfig, NetworkExecutionInput, NetworkExecutionOptions, NetworkExecutionResult, NetworkStreamChunk } from "./types/index.js";
9
- import type { CompactionConfig, CompactionResult, SpanData, ObservabilityConfig, MetricsSummary, MCPToolAnnotations, TraceView, AuthenticatedContext, AuthProvider, JsonObject, NeuroLinkEvents, TypedEventEmitter, MCPEnhancementsConfig, NeuroLinkAuthConfig, NeurolinkConstructorConfig, ChatMessage, ExternalMCPOperationResult, ExternalMCPServerInstance, ExternalMCPToolInfo, GenerateOptions, GenerateResult, ProviderStatus, TextGenerationOptions, TextGenerationResult, MCPExecutableTool, MCPServerInfo, MCPStatus, StreamOptions, StreamResult, ToolExecutionContext, ToolExecutionSummary, ToolInfo, ToolRegistrationOptions, BatchOperationResult, StreamGenerationEndContext, ToolRoutingServerDescriptor, ToolDedupConfig, ToolConfig } from "./types/index.js";
9
+ import type { CompactionConfig, CompactionResult, SpanData, ObservabilityConfig, MetricsSummary, MCPToolAnnotations, TraceView, AuthenticatedContext, AuthProvider, JsonObject, NeuroLinkEvents, TypedEventEmitter, MCPEnhancementsConfig, NeuroLinkAuthConfig, NeurolinkConstructorConfig, ChatMessage, ExternalMCPOperationResult, ExternalMCPServerInstance, ExternalMCPToolInfo, GenerateOptions, GenerateResult, ProviderStatus, TextGenerationOptions, TextGenerationResult, MCPExecutableTool, MCPServerInfo, MCPStatus, StreamOptions, StreamResult, ToolExecutionContext, ToolExecutionSummary, ToolInfo, ToolRegistrationOptions, BatchOperationResult, StreamGenerationEndContext, ToolRoutingServerDescriptor, ToolDedupConfig, ToolConfig, KnowledgeEngineStatus } from "./types/index.js";
10
10
  import { ConversationMemoryManager } from "./core/conversationMemoryManager.js";
11
11
  import type { RedisConversationMemoryManager } from "./core/redisConversationMemoryManager.js";
12
12
  import { ExternalServerManager } from "./mcp/externalServerManager.js";
@@ -107,6 +107,7 @@ export declare class NeuroLink {
107
107
  private toolRoutingConfig?;
108
108
  private toolRoutingCacheInstance?;
109
109
  private toolRoutingVectorCache?;
110
+ private knowledgeGroundingEngine?;
110
111
  private toolDedupConfig?;
111
112
  private toolsConfig?;
112
113
  /** Session-scoped pins of tools discovered via search_tools (tools.discovery mode). */
@@ -629,6 +630,7 @@ export declare class NeuroLink {
629
630
  * @param optionsOrPrompt.maxTokens - Maximum tokens to generate
630
631
  * @param optionsOrPrompt.thinkingConfig - Extended thinking configuration (thinkingLevel: 'minimal'|'low'|'medium'|'high')
631
632
  * @param optionsOrPrompt.context - Context with conversationId and userId for memory
633
+ * @param optionsOrPrompt.useKnowledgeGrounding - Whether to use the instance's configured knowledge for this call
632
634
  * @returns Promise resolving to generation result with content and metadata
633
635
  *
634
636
  * @example Basic text generation
@@ -904,6 +906,7 @@ export declare class NeuroLink {
904
906
  * @param options.enableEvaluation - Whether to include response quality evaluation
905
907
  * @param options.context - Additional context for the request
906
908
  * @param options.evaluationDomain - Domain for specialized evaluation
909
+ * @param options.useKnowledgeGrounding - Whether to use the instance's configured knowledge for this call
907
910
  *
908
911
  * @returns Promise resolving to StreamResult with an async iterable stream
909
912
  *
@@ -989,6 +992,16 @@ export declare class NeuroLink {
989
992
  * alone does not activate it.
990
993
  */
991
994
  setToolRoutingServers(servers: ToolRoutingServerDescriptor[]): void;
995
+ /** Knowledge-grounding engine health (null when it was not configured). */
996
+ getKnowledgeStatus(): KnowledgeEngineStatus | null;
997
+ private appendKnowledgeGroundingBlockToSystemPrompt;
998
+ /**
999
+ * Retrieve knowledge grounding for a public generate/stream call without
1000
+ * mutating its options. The outer call boundary decides how to apply the
1001
+ * returned context. Returns undefined when the call does not opt in,
1002
+ * grounding is disabled/not applicable, or retrieval fails open.
1003
+ */
1004
+ private retrieveKnowledgeGrounding;
992
1005
  private validateStreamRequestOptions;
993
1006
  private maybeHandleWorkflowStreamRequest;
994
1007
  private runStandardStreamRequest;
package/dist/neurolink.js CHANGED
@@ -32,6 +32,7 @@ import { SYSTEM_LIMITS, DEFAULT_TOOL_ROUTING_TIMEOUT_MS, MIN_RECOVERY_TURN_BUDGE
32
32
  import { ConversationMemoryManager } from "./core/conversationMemoryManager.js";
33
33
  import { buildToolRoutingCatalog, buildRoutingQueryFromHistory, resolveToolRoutingExclusions, } from "./core/toolRouting.js";
34
34
  import { ToolRoutingCache } from "./core/toolRoutingCache.js";
35
+ import { DEFAULT_RECENT_TURNS, KnowledgeGroundingEngine, } from "./knowledge/index.js";
35
36
  import { AIProviderFactory } from "./core/factory.js";
36
37
  import { createToolEventPayload } from "./core/toolEvents.js";
37
38
  import { ProviderRegistry } from "./factories/providerRegistry.js";
@@ -405,6 +406,9 @@ export class NeuroLink {
405
406
  // vectors are computed once. Cleared when the catalog changes via
406
407
  // setToolRoutingServers() so stale vectors are never reused.
407
408
  toolRoutingVectorCache;
409
+ // Knowledge grounding: lexical-first host-supplied retrieval engine. Built
410
+ // once from constructor config and undefined unless grounding is enabled.
411
+ knowledgeGroundingEngine;
408
412
  // Opt-in tool-signature deduplication config.
409
413
  toolDedupConfig;
410
414
  toolsConfig;
@@ -837,6 +841,18 @@ export class NeuroLink {
837
841
  // multiple NeuroLink instances.
838
842
  this.toolRoutingConfig = { ...config.toolRouting };
839
843
  }
844
+ const knowledgeGroundingConfig = config?.knowledgeGrounding;
845
+ if (knowledgeGroundingConfig?.enabled) {
846
+ if (Array.isArray(knowledgeGroundingConfig.sources) &&
847
+ knowledgeGroundingConfig.sources.length > 0) {
848
+ // The engine builds its immutable index asynchronously; eligible
849
+ // generate() and stream() calls await readiness before retrieval.
850
+ this.knowledgeGroundingEngine = new KnowledgeGroundingEngine(knowledgeGroundingConfig);
851
+ }
852
+ else {
853
+ logger.warn("[KnowledgeGrounding] enabled but no sources were provided; grounding disabled for this instance");
854
+ }
855
+ }
840
856
  if (config?.toolDedup) {
841
857
  this.toolDedupConfig = { ...config.toolDedup };
842
858
  }
@@ -853,7 +869,9 @@ export class NeuroLink {
853
869
  // generate() (marked so it never recursively re-routes). Fails open.
854
870
  this.classifierRouter = config?.classifierRouter?.enabled
855
871
  ? new ClassifierRouter(config.classifierRouter, {
856
- generate: (genOptions) => this.generate(genOptions),
872
+ generate: (genOptions) => this.generate({
873
+ ...genOptions,
874
+ }),
857
875
  logger: {
858
876
  debug: (message, meta) => logger.debug(message, meta),
859
877
  warn: (message, meta) => logger.warn(message, meta),
@@ -3045,6 +3063,7 @@ Current user's request: ${currentInput}`;
3045
3063
  * @param optionsOrPrompt.maxTokens - Maximum tokens to generate
3046
3064
  * @param optionsOrPrompt.thinkingConfig - Extended thinking configuration (thinkingLevel: 'minimal'|'low'|'medium'|'high')
3047
3065
  * @param optionsOrPrompt.context - Context with conversationId and userId for memory
3066
+ * @param optionsOrPrompt.useKnowledgeGrounding - Whether to use the instance's configured knowledge for this call
3048
3067
  * @returns Promise resolving to generation result with content and metadata
3049
3068
  *
3050
3069
  * @example Basic text generation
@@ -3131,9 +3150,22 @@ Current user's request: ${currentInput}`;
3131
3150
  if (typeof optionsOrPrompt !== "string") {
3132
3151
  optionsOrPrompt = cloneOptionsForCallIsolation(optionsOrPrompt);
3133
3152
  }
3153
+ // Retrieve once at the public call boundary so fallback attempts reuse the
3154
+ // same grounding block and internal preparation cannot inject it twice.
3155
+ const groundingOptions = typeof optionsOrPrompt === "string"
3156
+ ? { input: { text: optionsOrPrompt } }
3157
+ : optionsOrPrompt;
3158
+ const knowledgeOutcome = await this.retrieveKnowledgeGrounding(groundingOptions);
3159
+ if (knowledgeOutcome?.ephemeralContext) {
3160
+ const block = knowledgeOutcome.ephemeralContext.content;
3161
+ optionsOrPrompt = {
3162
+ ...groundingOptions,
3163
+ systemPrompt: this.appendKnowledgeGroundingBlockToSystemPrompt(groundingOptions.systemPrompt, block),
3164
+ };
3165
+ }
3134
3166
  const startedAt = Date.now();
3135
3167
  try {
3136
- return await this.runWithFallbackOrchestration(optionsOrPrompt, "generate", (opts) => {
3168
+ const result = await this.runWithFallbackOrchestration(optionsOrPrompt, "generate", (opts) => {
3137
3169
  // Capture root-ness before startActiveSpan makes generateSpan active.
3138
3170
  // The actual guest-rescue stamp is deferred to executeGenerateRequest,
3139
3171
  // AFTER prepareGenerateRequest merges auth/requestContext-derived
@@ -3142,6 +3174,10 @@ Current user's request: ${currentInput}`;
3142
3174
  const generateIsRoot = !trace.getSpan(context.active());
3143
3175
  return tracers.sdk.startActiveSpan("neurolink.generate", { kind: SpanKind.INTERNAL }, (generateSpan) => this.executeGenerateWithMetricsContext(opts, generateSpan, generateIsRoot));
3144
3176
  });
3177
+ if (knowledgeOutcome) {
3178
+ result.knowledge = knowledgeOutcome.metadata;
3179
+ }
3180
+ return result;
3145
3181
  }
3146
3182
  catch (error) {
3147
3183
  // Lifecycle middleware (wrapGenerate.catch in builtin/lifecycle.ts)
@@ -6204,6 +6240,7 @@ Current user's request: ${currentInput}`;
6204
6240
  * @param options.enableEvaluation - Whether to include response quality evaluation
6205
6241
  * @param options.context - Additional context for the request
6206
6242
  * @param options.evaluationDomain - Domain for specialized evaluation
6243
+ * @param options.useKnowledgeGrounding - Whether to use the instance's configured knowledge for this call
6207
6244
  *
6208
6245
  * @returns Promise resolving to StreamResult with an async iterable stream
6209
6246
  *
@@ -6261,8 +6298,23 @@ Current user's request: ${currentInput}`;
6261
6298
  // top-level keys and left `options.input` shared with the caller.
6262
6299
  options = cloneOptionsForCallIsolation(options);
6263
6300
  const startedAt = Date.now();
6301
+ // Retrieve once before provider/model fallback orchestration. Every fallback
6302
+ // receives the same explicitly enriched options, without the retrieval helper
6303
+ // mutating its input or injecting the same block more than once.
6304
+ const knowledgeOutcome = await this.retrieveKnowledgeGrounding(options);
6305
+ if (knowledgeOutcome?.ephemeralContext) {
6306
+ const block = knowledgeOutcome.ephemeralContext.content;
6307
+ options = {
6308
+ ...options,
6309
+ systemPrompt: this.appendKnowledgeGroundingBlockToSystemPrompt(options.systemPrompt, block),
6310
+ };
6311
+ }
6264
6312
  try {
6265
- return await this.streamWithIterationFallback(options);
6313
+ const result = await this.streamWithIterationFallback(options);
6314
+ if (knowledgeOutcome) {
6315
+ result.knowledge = knowledgeOutcome.metadata;
6316
+ }
6317
+ return result;
6266
6318
  }
6267
6319
  catch (error) {
6268
6320
  // Mirror generate(): fire consumer onError for failures that
@@ -6930,6 +6982,63 @@ Current user's request: ${currentInput}`;
6930
6982
  // to recompute exclusions against the new server/tool set.
6931
6983
  this.toolRoutingCacheInstance = undefined;
6932
6984
  }
6985
+ /** Knowledge-grounding engine health (null when it was not configured). */
6986
+ getKnowledgeStatus() {
6987
+ return this.knowledgeGroundingEngine?.getStatus() ?? null;
6988
+ }
6989
+ appendKnowledgeGroundingBlockToSystemPrompt(systemPrompt, block) {
6990
+ if (typeof systemPrompt === "function") {
6991
+ const originalSystemPrompt = systemPrompt;
6992
+ return async (context) => {
6993
+ const resolved = await resolveDynamicArgument(originalSystemPrompt, context);
6994
+ return resolved.value ? `${resolved.value}\n\n${block}` : block;
6995
+ };
6996
+ }
6997
+ return systemPrompt ? `${systemPrompt}\n\n${block}` : block;
6998
+ }
6999
+ /**
7000
+ * Retrieve knowledge grounding for a public generate/stream call without
7001
+ * mutating its options. The outer call boundary decides how to apply the
7002
+ * returned context. Returns undefined when the call does not opt in,
7003
+ * grounding is disabled/not applicable, or retrieval fails open.
7004
+ */
7005
+ async retrieveKnowledgeGrounding(options) {
7006
+ const engine = this.knowledgeGroundingEngine;
7007
+ if (!engine ||
7008
+ !engine.isEnabled() ||
7009
+ options.useKnowledgeGrounding !== true) {
7010
+ return undefined;
7011
+ }
7012
+ const query = options.input?.text;
7013
+ if (!query) {
7014
+ return undefined;
7015
+ }
7016
+ try {
7017
+ const conversationMessages = options.conversationMessages !== undefined
7018
+ ? options.conversationMessages
7019
+ : await this.fetchRecentRoutingHistory(options);
7020
+ const recentTurns = conversationMessages
7021
+ .filter((message) => message.role === "user" || message.role === "assistant")
7022
+ .slice(-DEFAULT_RECENT_TURNS)
7023
+ .map((message) => ({
7024
+ role: message.role === "assistant"
7025
+ ? "assistant"
7026
+ : "user",
7027
+ text: typeof message.content === "string" ? message.content : "",
7028
+ }));
7029
+ return await engine.ground({
7030
+ query,
7031
+ recentTurns,
7032
+ scope: options.knowledgeContext,
7033
+ });
7034
+ }
7035
+ catch (error) {
7036
+ logger.warn("[KnowledgeGrounding] grounding hook failed open", {
7037
+ error: String(error),
7038
+ });
7039
+ return undefined;
7040
+ }
7041
+ }
6933
7042
  async validateStreamRequestOptions(options, startTime) {
6934
7043
  await this.validateStreamInput(options);
6935
7044
  // Input validation for stream
@@ -13,6 +13,7 @@ import type { ModelPoolConfig } from "./modelPool.js";
13
13
  import type { RequestRouter } from "./requestRouter.js";
14
14
  import type { ClassifierRouterConfig } from "./classifierRouter.js";
15
15
  import type { SkillsConfig } from "./skills.js";
16
+ import type { KnowledgeGroundingConfig } from "./knowledge.js";
16
17
  /**
17
18
  * Main NeuroLink configuration type
18
19
  */
@@ -130,6 +131,17 @@ export type NeurolinkConstructorConfig = {
130
131
  * Opt-in and fails open on read paths. See {@link SkillsConfig}.
131
132
  */
132
133
  skills?: SkillsConfig;
134
+ /**
135
+ * Knowledge grounding: lexical-first host-supplied knowledge retrieval. When
136
+ * enabled with at least one source, a deterministic in-memory retrieval runs
137
+ * before each generate()/stream() turn — independently of tool routing — and
138
+ * attaches a token-bounded, ephemeral knowledge block to the model call. No
139
+ * embeddings or vector store. Opt-in (`enabled: false` by default) and fails
140
+ * open: any retrieval failure leaves the turn ungrounded. Sources are fixed
141
+ * for the lifetime of the instance. See
142
+ * {@link KnowledgeGroundingConfig}.
143
+ */
144
+ knowledgeGrounding?: KnowledgeGroundingConfig;
133
145
  };
134
146
  /**
135
147
  * Configuration for MCP enhancement modules wired into generate()/stream() paths.