@juspay/neurolink 10.3.0 → 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.
- package/CHANGELOG.md +12 -0
- package/dist/browser/neurolink.min.js +430 -417
- package/dist/cli/loop/optionsSchema.js +4 -0
- package/dist/constants/contextWindows.d.ts +24 -0
- package/dist/constants/contextWindows.js +50 -0
- package/dist/context/errorDetection.d.ts +6 -0
- package/dist/context/errorDetection.js +18 -0
- package/dist/context/stepBudgetGuard.d.ts +17 -3
- package/dist/context/stepBudgetGuard.js +53 -14
- package/dist/core/baseProvider.d.ts +12 -0
- package/dist/core/baseProvider.js +18 -0
- package/dist/core/modules/GenerationHandler.js +208 -42
- package/dist/core/modules/ToolsManager.d.ts +17 -0
- package/dist/core/modules/ToolsManager.js +99 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/knowledge/context.d.ts +18 -0
- package/dist/knowledge/context.js +91 -0
- package/dist/knowledge/defaults.d.ts +24 -0
- package/dist/knowledge/defaults.js +29 -0
- package/dist/knowledge/engine.d.ts +35 -0
- package/dist/knowledge/engine.js +179 -0
- package/dist/knowledge/index.d.ts +15 -0
- package/dist/knowledge/index.js +15 -0
- package/dist/knowledge/indexCache.d.ts +19 -0
- package/dist/knowledge/indexCache.js +109 -0
- package/dist/knowledge/knowledgeIndex.d.ts +41 -0
- package/dist/knowledge/knowledgeIndex.js +204 -0
- package/dist/knowledge/normalize.d.ts +32 -0
- package/dist/knowledge/normalize.js +74 -0
- package/dist/knowledge/resolve.d.ts +18 -0
- package/dist/knowledge/resolve.js +156 -0
- package/dist/knowledge/retrieval.d.ts +16 -0
- package/dist/knowledge/retrieval.js +221 -0
- package/dist/lib/constants/contextWindows.d.ts +24 -0
- package/dist/lib/constants/contextWindows.js +50 -0
- package/dist/lib/context/errorDetection.d.ts +6 -0
- package/dist/lib/context/errorDetection.js +18 -0
- package/dist/lib/context/stepBudgetGuard.d.ts +17 -3
- package/dist/lib/context/stepBudgetGuard.js +53 -14
- package/dist/lib/core/baseProvider.d.ts +12 -0
- package/dist/lib/core/baseProvider.js +18 -0
- package/dist/lib/core/modules/GenerationHandler.js +208 -42
- package/dist/lib/core/modules/ToolsManager.d.ts +17 -0
- package/dist/lib/core/modules/ToolsManager.js +99 -1
- package/dist/lib/files/fileTools.d.ts +1 -1
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.js +3 -0
- package/dist/lib/knowledge/context.d.ts +18 -0
- package/dist/lib/knowledge/context.js +92 -0
- package/dist/lib/knowledge/defaults.d.ts +24 -0
- package/dist/lib/knowledge/defaults.js +30 -0
- package/dist/lib/knowledge/engine.d.ts +35 -0
- package/dist/lib/knowledge/engine.js +180 -0
- package/dist/lib/knowledge/index.d.ts +15 -0
- package/dist/lib/knowledge/index.js +16 -0
- package/dist/lib/knowledge/indexCache.d.ts +19 -0
- package/dist/lib/knowledge/indexCache.js +110 -0
- package/dist/lib/knowledge/knowledgeIndex.d.ts +41 -0
- package/dist/lib/knowledge/knowledgeIndex.js +205 -0
- package/dist/lib/knowledge/normalize.d.ts +32 -0
- package/dist/lib/knowledge/normalize.js +75 -0
- package/dist/lib/knowledge/resolve.d.ts +18 -0
- package/dist/lib/knowledge/resolve.js +157 -0
- package/dist/lib/knowledge/retrieval.d.ts +16 -0
- package/dist/lib/knowledge/retrieval.js +222 -0
- package/dist/lib/mcp/toolDiscoveryService.js +59 -20
- package/dist/lib/neurolink.d.ts +14 -1
- package/dist/lib/neurolink.js +142 -12
- package/dist/lib/providers/litellm.d.ts +27 -19
- package/dist/lib/providers/litellm.js +171 -92
- package/dist/lib/providers/openaiChatCompletionsBase.d.ts +37 -1
- package/dist/lib/providers/openaiChatCompletionsBase.js +201 -33
- package/dist/lib/providers/openaiChatCompletionsClient.d.ts +23 -5
- package/dist/lib/providers/openaiChatCompletionsClient.js +94 -14
- package/dist/lib/proxy/proxyFetch.d.ts +17 -0
- package/dist/lib/proxy/proxyFetch.js +42 -4
- package/dist/lib/types/config.d.ts +12 -0
- package/dist/lib/types/conversation.d.ts +1 -1
- package/dist/lib/types/dynamic.d.ts +12 -0
- package/dist/lib/types/generate.d.ts +32 -2
- package/dist/lib/types/index.d.ts +1 -0
- package/dist/lib/types/index.js +1 -0
- package/dist/lib/types/knowledge.d.ts +342 -0
- package/dist/lib/types/knowledge.js +30 -0
- package/dist/lib/types/openaiCompatible.d.ts +2 -0
- package/dist/lib/types/providers.d.ts +9 -0
- package/dist/lib/types/stream.d.ts +14 -0
- package/dist/lib/utils/errorHandling.js +8 -2
- package/dist/lib/utils/schemaConversion.d.ts +16 -0
- package/dist/lib/utils/schemaConversion.js +165 -8
- package/dist/lib/utils/timeout.d.ts +22 -0
- package/dist/lib/utils/timeout.js +72 -12
- package/dist/lib/utils/tokenLimits.js +22 -0
- package/dist/lib/utils/toolCallRepair.d.ts +8 -0
- package/dist/lib/utils/toolCallRepair.js +4 -1
- package/dist/mcp/toolDiscoveryService.js +59 -20
- package/dist/neurolink.d.ts +14 -1
- package/dist/neurolink.js +142 -12
- package/dist/providers/litellm.d.ts +27 -19
- package/dist/providers/litellm.js +171 -92
- package/dist/providers/openaiChatCompletionsBase.d.ts +37 -1
- package/dist/providers/openaiChatCompletionsBase.js +201 -33
- package/dist/providers/openaiChatCompletionsClient.d.ts +23 -5
- package/dist/providers/openaiChatCompletionsClient.js +94 -14
- package/dist/proxy/proxyFetch.d.ts +17 -0
- package/dist/proxy/proxyFetch.js +42 -4
- package/dist/types/config.d.ts +12 -0
- package/dist/types/conversation.d.ts +1 -1
- package/dist/types/dynamic.d.ts +12 -0
- package/dist/types/generate.d.ts +32 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/knowledge.d.ts +342 -0
- package/dist/types/knowledge.js +29 -0
- package/dist/types/openaiCompatible.d.ts +2 -0
- package/dist/types/providers.d.ts +9 -0
- package/dist/types/stream.d.ts +14 -0
- package/dist/utils/errorHandling.js +8 -2
- package/dist/utils/schemaConversion.d.ts +16 -0
- package/dist/utils/schemaConversion.js +165 -8
- package/dist/utils/timeout.d.ts +22 -0
- package/dist/utils/timeout.js +72 -12
- package/dist/utils/tokenLimits.js +22 -0
- package/dist/utils/toolCallRepair.d.ts +8 -0
- package/dist/utils/toolCallRepair.js +4 -1
- package/package.json +4 -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,29 @@
|
|
|
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 {};
|
|
@@ -226,6 +226,8 @@ export type StreamLoopArgs = {
|
|
|
226
226
|
openAITools: OpenAICompatChatTool[] | undefined;
|
|
227
227
|
openAIToolChoice: OpenAICompatToolChoiceWire | undefined;
|
|
228
228
|
toolsRecord: Record<string, Tool>;
|
|
229
|
+
/** Wire → registered tool-name map when sanitization was needed (see buildWireToolNameMaps). */
|
|
230
|
+
toolNameFromWire?: Map<string, string>;
|
|
229
231
|
emitter: TypedEventEmitter<NeuroLinkEvents> | undefined;
|
|
230
232
|
toolsUsed: string[];
|
|
231
233
|
toolExecutionSummaries: ToolExecutionSummaryInternal[];
|
|
@@ -601,6 +601,15 @@ export type AIProvider = {
|
|
|
601
601
|
* external AIProvider implementations — callers treat absence as `true`.
|
|
602
602
|
*/
|
|
603
603
|
supportsTools?(): boolean;
|
|
604
|
+
/**
|
|
605
|
+
* Ensure runtime-discovered model limits (context window, output-token
|
|
606
|
+
* ceiling) are registered before budget math runs. Implemented by
|
|
607
|
+
* BaseProvider (default no-op); providers with a discovery source override
|
|
608
|
+
* it (LiteLLM `/model/info`). Must never reject — discovery failure
|
|
609
|
+
* degrades to static defaults. Optional for compile compatibility with
|
|
610
|
+
* external AIProvider implementations — callers treat absence as no-op.
|
|
611
|
+
*/
|
|
612
|
+
ensureModelLimits?(): Promise<void>;
|
|
604
613
|
};
|
|
605
614
|
/**
|
|
606
615
|
* Provider attempt result for iteration tracking (converted from interface)
|
package/dist/types/stream.d.ts
CHANGED
|
@@ -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;
|
|
@@ -1012,12 +1012,18 @@ export class ErrorFactory {
|
|
|
1012
1012
|
* Timeout wrapper for async operations
|
|
1013
1013
|
*/
|
|
1014
1014
|
export async function withTimeout(promise, timeoutMs, timeoutError) {
|
|
1015
|
+
let timer;
|
|
1015
1016
|
const timeoutPromise = new Promise((_, reject) => {
|
|
1016
|
-
setTimeout(() => {
|
|
1017
|
+
timer = setTimeout(() => {
|
|
1017
1018
|
reject(timeoutError || new Error(`Operation timed out after ${timeoutMs}ms`));
|
|
1018
1019
|
}, timeoutMs);
|
|
1019
1020
|
});
|
|
1020
|
-
|
|
1021
|
+
try {
|
|
1022
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
1023
|
+
}
|
|
1024
|
+
finally {
|
|
1025
|
+
clearTimeout(timer);
|
|
1026
|
+
}
|
|
1021
1027
|
}
|
|
1022
1028
|
/**
|
|
1023
1029
|
* Retry mechanism for retriable operations
|
|
@@ -29,6 +29,22 @@ export declare function ensureNestedSchemaTypes(schema: Record<string, unknown>)
|
|
|
29
29
|
*/
|
|
30
30
|
export declare function convertZodToJsonSchema(zodSchema: ZodUnknownSchema, target?: "jsonSchema7" | "openApi3"): object;
|
|
31
31
|
export declare function normalizeJsonSchemaObject(schema: Record<string, unknown> | undefined | null): Record<string, unknown>;
|
|
32
|
+
/**
|
|
33
|
+
* Normalize a JSON Schema for the OpenAI chat-completions `tools` wire
|
|
34
|
+
* block. Generic proxied backends (LiteLLM → vllm/GLM/Qwen, local servers)
|
|
35
|
+
* render tool schemas into chat templates more or less verbatim, so `$ref`
|
|
36
|
+
* indirection, `$defs` containers, `$schema` annotations, and zod's
|
|
37
|
+
* nullable `anyOf` pattern all measurably degrade argument generation —
|
|
38
|
+
* this is the parity gap behind "the model can't find the right arguments"
|
|
39
|
+
* on litellm while the same tools work on Gemini/Claude native paths
|
|
40
|
+
* (which sanitize schemas before the wire).
|
|
41
|
+
*
|
|
42
|
+
* Pipeline: strip annotation keys → inline local `$ref`/`$defs`/
|
|
43
|
+
* `definitions` → collapse nullable variants → guarantee a top-level object
|
|
44
|
+
* shape. Identity for already-clean schemas; `description`, `required`,
|
|
45
|
+
* `enum`, and `default` — what models actually read — are always preserved.
|
|
46
|
+
*/
|
|
47
|
+
export declare function normalizeWireToolSchema(schema: unknown): Record<string, unknown>;
|
|
32
48
|
/**
|
|
33
49
|
* Check if a value is a Zod schema
|
|
34
50
|
*/
|
|
@@ -80,9 +80,11 @@ function safePercentDecode(segment) {
|
|
|
80
80
|
* - Circular reference detection to prevent infinite loops
|
|
81
81
|
*/
|
|
82
82
|
export function inlineJsonSchema(schema, definitions, visited = new Set(), rootSchema) {
|
|
83
|
-
// Use definitions from schema if not provided
|
|
83
|
+
// Use definitions from schema if not provided. Modern MCP servers and
|
|
84
|
+
// zod v4's native toJSONSchema emit the 2020-12 `$defs` keyword; older
|
|
85
|
+
// emitters use draft-07 `definitions`. Support both.
|
|
84
86
|
const defs = definitions ||
|
|
85
|
-
schema.definitions;
|
|
87
|
+
(schema.definitions ?? schema.$defs);
|
|
86
88
|
// Keep track of the root schema for deep ref resolution
|
|
87
89
|
const root = rootSchema || schema;
|
|
88
90
|
// Handle $ref at current level
|
|
@@ -94,10 +96,14 @@ export function inlineJsonSchema(schema, definitions, visited = new Set(), rootS
|
|
|
94
96
|
// Return a simple object placeholder for circular refs
|
|
95
97
|
return { type: "object" };
|
|
96
98
|
}
|
|
97
|
-
// Try simple definition lookup first (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
// Try simple definition lookup first (#/definitions/SomeName or the
|
|
100
|
+
// 2020-12 #/$defs/SomeName form)
|
|
101
|
+
if (refPath.startsWith("#/definitions/") ||
|
|
102
|
+
refPath.startsWith("#/$defs/")) {
|
|
103
|
+
const defName = refPath
|
|
104
|
+
.replace("#/definitions/", "")
|
|
105
|
+
.replace("#/$defs/", "");
|
|
106
|
+
// Check if it's a simple definition name (no slashes after the prefix)
|
|
101
107
|
if (!defName.includes("/") && defs && defs[defName]) {
|
|
102
108
|
visited.add(refPath);
|
|
103
109
|
const resolved = inlineJsonSchema({ ...defs[defName] }, defs, visited, root);
|
|
@@ -124,8 +130,8 @@ export function inlineJsonSchema(schema, definitions, visited = new Set(), rootS
|
|
|
124
130
|
// Create result without $ref and definitions
|
|
125
131
|
const result = {};
|
|
126
132
|
for (const [key, value] of Object.entries(schema)) {
|
|
127
|
-
// Skip $ref and
|
|
128
|
-
if (key === "$ref" || key === "definitions") {
|
|
133
|
+
// Skip $ref and definition-container keys (both draft-07 and 2020-12)
|
|
134
|
+
if (key === "$ref" || key === "definitions" || key === "$defs") {
|
|
129
135
|
continue;
|
|
130
136
|
}
|
|
131
137
|
// Recursively process nested schemas
|
|
@@ -402,6 +408,157 @@ function ensureTypeField(schema) {
|
|
|
402
408
|
}
|
|
403
409
|
return schema;
|
|
404
410
|
}
|
|
411
|
+
/** JSON Schema keys whose values are themselves schemas (single). */
|
|
412
|
+
const SCHEMA_VALUE_KEYS = new Set([
|
|
413
|
+
"items",
|
|
414
|
+
"additionalProperties",
|
|
415
|
+
"not",
|
|
416
|
+
"if",
|
|
417
|
+
"then",
|
|
418
|
+
"else",
|
|
419
|
+
"contains",
|
|
420
|
+
"propertyNames",
|
|
421
|
+
]);
|
|
422
|
+
/** JSON Schema keys whose values are arrays of schemas. */
|
|
423
|
+
const SCHEMA_ARRAY_KEYS = new Set(["allOf", "anyOf", "oneOf", "prefixItems"]);
|
|
424
|
+
/** JSON Schema keys whose values are name → schema maps. */
|
|
425
|
+
const SCHEMA_MAP_KEYS = new Set([
|
|
426
|
+
"properties",
|
|
427
|
+
"patternProperties",
|
|
428
|
+
"$defs",
|
|
429
|
+
"definitions",
|
|
430
|
+
]);
|
|
431
|
+
/**
|
|
432
|
+
* Annotation keys that carry no validation semantics for a model and that
|
|
433
|
+
* generic OpenAI-compatible backends (vllm, GLM/Qwen chat templates, local
|
|
434
|
+
* servers) may render into the prompt verbatim, confusing argument
|
|
435
|
+
* generation. Removed only at SCHEMA positions — never inside data values
|
|
436
|
+
* like `default`, `const`, `enum` or `examples`, where `$id` etc. are
|
|
437
|
+
* legitimate payload.
|
|
438
|
+
*/
|
|
439
|
+
const SCHEMA_ANNOTATION_KEYS = new Set(["$schema", "$id", "$comment"]);
|
|
440
|
+
/** Walk schema positions only, dropping annotation-only keys. */
|
|
441
|
+
function stripSchemaAnnotations(schema) {
|
|
442
|
+
const result = {};
|
|
443
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
444
|
+
if (SCHEMA_ANNOTATION_KEYS.has(key)) {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
if (SCHEMA_VALUE_KEYS.has(key) &&
|
|
448
|
+
value &&
|
|
449
|
+
typeof value === "object" &&
|
|
450
|
+
!Array.isArray(value)) {
|
|
451
|
+
result[key] = stripSchemaAnnotations(value);
|
|
452
|
+
}
|
|
453
|
+
else if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
|
|
454
|
+
result[key] = value.map((item) => item && typeof item === "object" && !Array.isArray(item)
|
|
455
|
+
? stripSchemaAnnotations(item)
|
|
456
|
+
: item);
|
|
457
|
+
}
|
|
458
|
+
else if (SCHEMA_MAP_KEYS.has(key) &&
|
|
459
|
+
value &&
|
|
460
|
+
typeof value === "object" &&
|
|
461
|
+
!Array.isArray(value)) {
|
|
462
|
+
const map = {};
|
|
463
|
+
for (const [name, sub] of Object.entries(value)) {
|
|
464
|
+
map[name] =
|
|
465
|
+
sub && typeof sub === "object" && !Array.isArray(sub)
|
|
466
|
+
? stripSchemaAnnotations(sub)
|
|
467
|
+
: sub;
|
|
468
|
+
}
|
|
469
|
+
result[key] = map;
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
result[key] = value;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return result;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Collapse the zod-emitted nullable pattern `anyOf/oneOf: [T, {type:"null"}]`
|
|
479
|
+
* into `{...T, type: [t, "null"]}`. Weaker OSS models handle a plain type
|
|
480
|
+
* array far better than composition keywords when choosing tool arguments.
|
|
481
|
+
* Conservative: only fires for exactly-two variants where the non-null
|
|
482
|
+
* variant has a primitive `type` string — everything else passes through.
|
|
483
|
+
*/
|
|
484
|
+
function collapseNullableVariants(schema) {
|
|
485
|
+
const result = {};
|
|
486
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
487
|
+
if (SCHEMA_VALUE_KEYS.has(key) &&
|
|
488
|
+
value &&
|
|
489
|
+
typeof value === "object" &&
|
|
490
|
+
!Array.isArray(value)) {
|
|
491
|
+
result[key] = collapseNullableVariants(value);
|
|
492
|
+
}
|
|
493
|
+
else if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(value)) {
|
|
494
|
+
result[key] = value.map((item) => item && typeof item === "object" && !Array.isArray(item)
|
|
495
|
+
? collapseNullableVariants(item)
|
|
496
|
+
: item);
|
|
497
|
+
}
|
|
498
|
+
else if (SCHEMA_MAP_KEYS.has(key) &&
|
|
499
|
+
value &&
|
|
500
|
+
typeof value === "object" &&
|
|
501
|
+
!Array.isArray(value)) {
|
|
502
|
+
const map = {};
|
|
503
|
+
for (const [name, sub] of Object.entries(value)) {
|
|
504
|
+
map[name] =
|
|
505
|
+
sub && typeof sub === "object" && !Array.isArray(sub)
|
|
506
|
+
? collapseNullableVariants(sub)
|
|
507
|
+
: sub;
|
|
508
|
+
}
|
|
509
|
+
result[key] = map;
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
result[key] = value;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
for (const compositionKey of ["anyOf", "oneOf"]) {
|
|
516
|
+
const variants = result[compositionKey];
|
|
517
|
+
if (!Array.isArray(variants) || variants.length !== 2) {
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
const isNullVariant = (v) => !!v &&
|
|
521
|
+
typeof v === "object" &&
|
|
522
|
+
v.type === "null";
|
|
523
|
+
const nullIndex = variants.findIndex(isNullVariant);
|
|
524
|
+
if (nullIndex === -1) {
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
const other = variants[1 - nullIndex];
|
|
528
|
+
if (!other ||
|
|
529
|
+
typeof other !== "object" ||
|
|
530
|
+
Array.isArray(other) ||
|
|
531
|
+
typeof other.type !== "string" ||
|
|
532
|
+
other.type === "null") {
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
// Merge: variant content + outer annotations (description etc.) win.
|
|
536
|
+
const { [compositionKey]: _dropped, ...outer } = result;
|
|
537
|
+
return { ...other, ...outer, type: [other.type, "null"] };
|
|
538
|
+
}
|
|
539
|
+
return result;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Normalize a JSON Schema for the OpenAI chat-completions `tools` wire
|
|
543
|
+
* block. Generic proxied backends (LiteLLM → vllm/GLM/Qwen, local servers)
|
|
544
|
+
* render tool schemas into chat templates more or less verbatim, so `$ref`
|
|
545
|
+
* indirection, `$defs` containers, `$schema` annotations, and zod's
|
|
546
|
+
* nullable `anyOf` pattern all measurably degrade argument generation —
|
|
547
|
+
* this is the parity gap behind "the model can't find the right arguments"
|
|
548
|
+
* on litellm while the same tools work on Gemini/Claude native paths
|
|
549
|
+
* (which sanitize schemas before the wire).
|
|
550
|
+
*
|
|
551
|
+
* Pipeline: strip annotation keys → inline local `$ref`/`$defs`/
|
|
552
|
+
* `definitions` → collapse nullable variants → guarantee a top-level object
|
|
553
|
+
* shape. Identity for already-clean schemas; `description`, `required`,
|
|
554
|
+
* `enum`, and `default` — what models actually read — are always preserved.
|
|
555
|
+
*/
|
|
556
|
+
export function normalizeWireToolSchema(schema) {
|
|
557
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
558
|
+
return { type: "object", properties: {} };
|
|
559
|
+
}
|
|
560
|
+
return ensureTypeField(collapseNullableVariants(inlineJsonSchema(stripSchemaAnnotations(schema))));
|
|
561
|
+
}
|
|
405
562
|
/**
|
|
406
563
|
* Check if a value is a Zod schema
|
|
407
564
|
*/
|