@juspay/neurolink 9.84.2 → 9.85.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 +6 -0
- package/dist/browser/neurolink.min.js +436 -401
- package/dist/cli/factories/commandFactory.d.ts +17 -0
- package/dist/cli/factories/commandFactory.js +254 -0
- package/dist/cli/parser.js +2 -0
- package/dist/cli/utils/skillsFlags.d.ts +10 -0
- package/dist/cli/utils/skillsFlags.js +22 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/lib/index.d.ts +5 -0
- package/dist/lib/index.js +6 -0
- package/dist/lib/neurolink.d.ts +28 -0
- package/dist/lib/neurolink.js +117 -0
- package/dist/lib/server/routes/agentRoutes.js +156 -1
- package/dist/lib/server/utils/validation.d.ts +32 -0
- package/dist/lib/server/utils/validation.js +18 -0
- package/dist/lib/session/globalSessionState.d.ts +10 -1
- package/dist/lib/session/globalSessionState.js +18 -0
- package/dist/lib/skills/skillMatcher.d.ts +20 -0
- package/dist/lib/skills/skillMatcher.js +80 -0
- package/dist/lib/skills/skillStoreRedis.d.ts +22 -0
- package/dist/lib/skills/skillStoreRedis.js +98 -0
- package/dist/lib/skills/skillStoreS3.d.ts +41 -0
- package/dist/lib/skills/skillStoreS3.js +233 -0
- package/dist/lib/skills/skillStores.d.ts +44 -0
- package/dist/lib/skills/skillStores.js +252 -0
- package/dist/lib/skills/skillTools.d.ts +19 -0
- package/dist/lib/skills/skillTools.js +340 -0
- package/dist/lib/skills/skillsManager.d.ts +54 -0
- package/dist/lib/skills/skillsManager.js +220 -0
- package/dist/lib/types/config.d.ts +10 -0
- package/dist/lib/types/generate.d.ts +8 -0
- package/dist/lib/types/index.d.ts +1 -0
- package/dist/lib/types/index.js +1 -0
- package/dist/lib/types/skills.d.ts +296 -0
- package/dist/lib/types/skills.js +17 -0
- package/dist/lib/types/stream.d.ts +8 -0
- package/dist/neurolink.d.ts +28 -0
- package/dist/neurolink.js +117 -0
- package/dist/server/routes/agentRoutes.js +156 -1
- package/dist/server/utils/validation.d.ts +32 -0
- package/dist/server/utils/validation.js +18 -0
- package/dist/session/globalSessionState.d.ts +10 -1
- package/dist/session/globalSessionState.js +18 -0
- package/dist/skills/skillMatcher.d.ts +20 -0
- package/dist/skills/skillMatcher.js +79 -0
- package/dist/skills/skillStoreRedis.d.ts +22 -0
- package/dist/skills/skillStoreRedis.js +97 -0
- package/dist/skills/skillStoreS3.d.ts +41 -0
- package/dist/skills/skillStoreS3.js +232 -0
- package/dist/skills/skillStores.d.ts +44 -0
- package/dist/skills/skillStores.js +251 -0
- package/dist/skills/skillTools.d.ts +19 -0
- package/dist/skills/skillTools.js +339 -0
- package/dist/skills/skillsManager.d.ts +54 -0
- package/dist/skills/skillsManager.js +219 -0
- package/dist/types/config.d.ts +10 -0
- package/dist/types/generate.d.ts +8 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/skills.d.ts +296 -0
- package/dist/types/skills.js +16 -0
- package/dist/types/stream.d.ts +8 -0
- package/package.json +2 -1
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native skills support — versioned, discoverable instruction packs
|
|
3
|
+
* (SOPs, playbooks, workflows) exposed to the model via progressive
|
|
4
|
+
* disclosure: a cheap name+description index up front, full instructions
|
|
5
|
+
* loaded on demand through built-in skill tools.
|
|
6
|
+
*
|
|
7
|
+
* Architecture mirrors the Hippocampus memory subsystem: a `skills` config
|
|
8
|
+
* on the NeuroLink constructor lazily initializes a SkillsManager, which
|
|
9
|
+
* auto-registers built-in tools (search_skills / list_skills, plus gated
|
|
10
|
+
* mutation tools) and optionally injects a compact skills index into the
|
|
11
|
+
* system prompt of each generate()/stream() call.
|
|
12
|
+
*
|
|
13
|
+
* Naming: every exported type carries a `Skill` prefix to satisfy the
|
|
14
|
+
* `unique-type-names` ESLint rule.
|
|
15
|
+
*/
|
|
16
|
+
/** Visibility of a skill: available everywhere, or only in specific scopes. */
|
|
17
|
+
export type SkillScopeKind = "global" | "scoped";
|
|
18
|
+
/** Lifecycle status. Deletes are soft — deprecated skills stay in storage. */
|
|
19
|
+
export type SkillLifecycleStatus = "active" | "deprecated";
|
|
20
|
+
/**
|
|
21
|
+
* A complete skill: index metadata plus the full `instructions` body.
|
|
22
|
+
* `instructions` is the expensive part — it is only hydrated for matched
|
|
23
|
+
* skills, never included in index listings or the prompt index.
|
|
24
|
+
*/
|
|
25
|
+
export type SkillDefinition = {
|
|
26
|
+
/** Stable unique identifier (UUID for created skills, or derived from filename). */
|
|
27
|
+
id: string;
|
|
28
|
+
/** Machine-friendly unique name (snake_case recommended), used for matching. */
|
|
29
|
+
name: string;
|
|
30
|
+
/** Human-readable display name shown in listings. */
|
|
31
|
+
displayName?: string;
|
|
32
|
+
/** One or two sentences describing when the skill applies — the matching signal. */
|
|
33
|
+
description: string;
|
|
34
|
+
/** Full step-by-step instructions the model follows when the skill matches. */
|
|
35
|
+
instructions: string;
|
|
36
|
+
/** Domain tags for filtering (e.g. ["payments", "escalation"]). */
|
|
37
|
+
tags?: string[];
|
|
38
|
+
/** Visibility. Default: "global". */
|
|
39
|
+
scope?: SkillScopeKind;
|
|
40
|
+
/** Scope identifiers this skill is limited to when scope === "scoped" (e.g. channel/team/tenant ids). */
|
|
41
|
+
scopeIds?: string[];
|
|
42
|
+
/** Monotonic version, bumped on every approved update. Default: 1. */
|
|
43
|
+
version?: number;
|
|
44
|
+
/** Lifecycle status. Default: "active". */
|
|
45
|
+
status?: SkillLifecycleStatus;
|
|
46
|
+
/** ISO timestamp of creation. */
|
|
47
|
+
createdAt?: string;
|
|
48
|
+
/** ISO timestamp of last update. */
|
|
49
|
+
updatedAt?: string;
|
|
50
|
+
/** Free-form host metadata (audit fields, approval references, …). */
|
|
51
|
+
metadata?: Record<string, unknown>;
|
|
52
|
+
};
|
|
53
|
+
/** Lightweight index entry — everything except the instructions body. */
|
|
54
|
+
export type SkillIndexItem = Omit<SkillDefinition, "instructions">;
|
|
55
|
+
/**
|
|
56
|
+
* Pluggable persistence backend. NeuroLink ships memory and filesystem
|
|
57
|
+
* stores; hosts plug their own (S3, database, …) via the "custom" storage
|
|
58
|
+
* type. `index()` must be cheap relative to `get()` — it backs every
|
|
59
|
+
* search and prompt-index build.
|
|
60
|
+
*/
|
|
61
|
+
export type SkillStore = {
|
|
62
|
+
/** Fetch one skill (with instructions) by id. Null when absent. */
|
|
63
|
+
get(id: string): Promise<SkillDefinition | null>;
|
|
64
|
+
/** Create or replace a skill. */
|
|
65
|
+
put(skill: SkillDefinition): Promise<void>;
|
|
66
|
+
/** Hard-remove a skill from storage. (Soft deletes go through put().) */
|
|
67
|
+
delete(id: string): Promise<void>;
|
|
68
|
+
/** List index entries (no instructions) for all stored skills. */
|
|
69
|
+
index(): Promise<SkillIndexItem[]>;
|
|
70
|
+
/** Optional: drop any internal caches (called after mutations). */
|
|
71
|
+
invalidate?(): void;
|
|
72
|
+
};
|
|
73
|
+
/** In-process store, optionally seeded. Good for tests and embedded use. */
|
|
74
|
+
export type SkillMemoryStorageConfig = {
|
|
75
|
+
type: "memory";
|
|
76
|
+
/** Initial skills to seed the store with. */
|
|
77
|
+
skills?: SkillDefinition[];
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Directory-backed store. Reads three layouts:
|
|
81
|
+
* - `<dir>/<id>.json` — one JSON-serialized SkillDefinition per file
|
|
82
|
+
* - `<dir>/<name>.md` — markdown with YAML frontmatter; body = instructions
|
|
83
|
+
* - `<dir>/<name>/SKILL.md` — Claude-skills-style directory layout
|
|
84
|
+
* Mutations always write `<id>.json`; markdown sources are read-only.
|
|
85
|
+
*/
|
|
86
|
+
export type SkillFilesystemStorageConfig = {
|
|
87
|
+
type: "filesystem";
|
|
88
|
+
/** Directory containing skill files. Created on first write if absent. */
|
|
89
|
+
path: string;
|
|
90
|
+
};
|
|
91
|
+
/** Host-provided store implementation (e.g. curator's S3 repository). */
|
|
92
|
+
export type SkillCustomStorageConfig = {
|
|
93
|
+
type: "custom";
|
|
94
|
+
store: SkillStore;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* S3-backed store. Layout: `<prefix>skills/<id>.json` per skill plus a
|
|
98
|
+
* `<prefix>index.json` document that is upserted on writes and rebuilt
|
|
99
|
+
* from a bucket listing when missing or corrupt (self-healing).
|
|
100
|
+
*
|
|
101
|
+
* Requires the optional peer `@aws-sdk/client-s3` to be installed in the
|
|
102
|
+
* host application (same pattern as memory's optional @juspay/hippocampus).
|
|
103
|
+
* Credentials default to the standard AWS provider chain when omitted.
|
|
104
|
+
*/
|
|
105
|
+
export type SkillS3StorageConfig = {
|
|
106
|
+
type: "s3";
|
|
107
|
+
bucket: string;
|
|
108
|
+
/** Key prefix inside the bucket. Default: "neurolink-skills/". */
|
|
109
|
+
prefix?: string;
|
|
110
|
+
region?: string;
|
|
111
|
+
/** Custom endpoint (MinIO, LocalStack, …). */
|
|
112
|
+
endpoint?: string;
|
|
113
|
+
/** Use path-style addressing (required by most S3-compatible stores). */
|
|
114
|
+
forcePathStyle?: boolean;
|
|
115
|
+
credentials?: {
|
|
116
|
+
accessKeyId: string;
|
|
117
|
+
secretAccessKey: string;
|
|
118
|
+
sessionToken?: string;
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Redis-backed store using NeuroLink's pooled Redis client (`redis` v5,
|
|
123
|
+
* already a core dependency). One JSON value per skill under
|
|
124
|
+
* `<keyPrefix><id>`; the index is derived via SCAN + MGET. Skills are
|
|
125
|
+
* persistent — no TTL is applied.
|
|
126
|
+
*/
|
|
127
|
+
export type SkillRedisStorageConfig = {
|
|
128
|
+
type: "redis";
|
|
129
|
+
url?: string;
|
|
130
|
+
host?: string;
|
|
131
|
+
port?: number;
|
|
132
|
+
username?: string;
|
|
133
|
+
password?: string;
|
|
134
|
+
db?: number;
|
|
135
|
+
/** Key prefix. Default: "neurolink:skills:". */
|
|
136
|
+
keyPrefix?: string;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Structural surface of the lazily-required @aws-sdk/client-s3 module —
|
|
140
|
+
* only the pieces the S3 skill store touches (same pattern as
|
|
141
|
+
* HippocampusModule for the optional memory peer).
|
|
142
|
+
*/
|
|
143
|
+
export type SkillS3ModuleSurface = {
|
|
144
|
+
S3Client: new (config: Record<string, unknown>) => {
|
|
145
|
+
send: (command: unknown) => Promise<unknown>;
|
|
146
|
+
};
|
|
147
|
+
GetObjectCommand: new (input: Record<string, unknown>) => unknown;
|
|
148
|
+
PutObjectCommand: new (input: Record<string, unknown>) => unknown;
|
|
149
|
+
DeleteObjectCommand: new (input: Record<string, unknown>) => unknown;
|
|
150
|
+
ListObjectsV2Command: new (input: Record<string, unknown>) => unknown;
|
|
151
|
+
};
|
|
152
|
+
/** Shape of the `<prefix>index.json` document maintained by the S3 store. */
|
|
153
|
+
export type SkillS3IndexDocument = {
|
|
154
|
+
lastUpdated: string;
|
|
155
|
+
skills: SkillIndexItem[];
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Minimal object-storage operations the S3 skill store runs on. The
|
|
159
|
+
* default implementation is created lazily from @aws-sdk/client-s3;
|
|
160
|
+
* tests and hosts with pre-built clients can inject their own.
|
|
161
|
+
*/
|
|
162
|
+
export type SkillS3ObjectOps = {
|
|
163
|
+
/** Fetch an object's body as a UTF-8 string. Null when the key is absent. */
|
|
164
|
+
getObject(key: string): Promise<string | null>;
|
|
165
|
+
putObject(key: string, body: string): Promise<void>;
|
|
166
|
+
deleteObject(key: string): Promise<void>;
|
|
167
|
+
/** List all object keys under a prefix (paginated internally). */
|
|
168
|
+
listKeys(prefix: string): Promise<string[]>;
|
|
169
|
+
};
|
|
170
|
+
export type SkillsStorageConfig = SkillMemoryStorageConfig | SkillFilesystemStorageConfig | SkillS3StorageConfig | SkillRedisStorageConfig | SkillCustomStorageConfig;
|
|
171
|
+
/** Query accepted by SkillsManager.search() and the search_skills tool. */
|
|
172
|
+
export type SkillSearchQuery = {
|
|
173
|
+
/** Keyword matched (case-insensitive substring) against name, displayName, and description. */
|
|
174
|
+
query?: string;
|
|
175
|
+
/** Tag filter, applied on top of the keyword match. */
|
|
176
|
+
tag?: string;
|
|
177
|
+
/** Scope filter: include global skills plus skills scoped to this id. */
|
|
178
|
+
scopeId?: string;
|
|
179
|
+
/** Maximum matches to hydrate. Defaults to SkillsConfig.maxMatches. */
|
|
180
|
+
limit?: number;
|
|
181
|
+
};
|
|
182
|
+
/** Input for creating a skill (id/version/status/timestamps are assigned by the manager). */
|
|
183
|
+
export type SkillCreateInput = {
|
|
184
|
+
name: string;
|
|
185
|
+
displayName?: string;
|
|
186
|
+
description: string;
|
|
187
|
+
instructions: string;
|
|
188
|
+
tags?: string[];
|
|
189
|
+
scope?: SkillScopeKind;
|
|
190
|
+
scopeIds?: string[];
|
|
191
|
+
metadata?: Record<string, unknown>;
|
|
192
|
+
};
|
|
193
|
+
/** Patch for updating a skill. Only provided fields change; version is bumped. */
|
|
194
|
+
export type SkillUpdateInput = Partial<SkillCreateInput>;
|
|
195
|
+
/** A proposed mutation, passed to the host's onMutationRequest gate. */
|
|
196
|
+
export type SkillMutationAction = {
|
|
197
|
+
type: "create";
|
|
198
|
+
skill: SkillCreateInput;
|
|
199
|
+
requestedBy?: string;
|
|
200
|
+
} | {
|
|
201
|
+
type: "update";
|
|
202
|
+
skillId: string;
|
|
203
|
+
patch: SkillUpdateInput;
|
|
204
|
+
requestedBy?: string;
|
|
205
|
+
} | {
|
|
206
|
+
type: "delete";
|
|
207
|
+
skillId: string;
|
|
208
|
+
requestedBy?: string;
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* Host decision for a proposed mutation.
|
|
212
|
+
* - "approved": NeuroLink applies the mutation immediately.
|
|
213
|
+
* - "rejected": nothing is written; `reason` is surfaced to the model.
|
|
214
|
+
* - "pending": the host queued the action for out-of-band approval
|
|
215
|
+
* (e.g. a Slack maker-checker flow) and will apply it itself later;
|
|
216
|
+
* `reference` is surfaced to the model (e.g. an approval ticket id).
|
|
217
|
+
*/
|
|
218
|
+
export type SkillMutationDecision = {
|
|
219
|
+
outcome: "approved";
|
|
220
|
+
} | {
|
|
221
|
+
outcome: "rejected";
|
|
222
|
+
reason?: string;
|
|
223
|
+
} | {
|
|
224
|
+
outcome: "pending";
|
|
225
|
+
reference?: string;
|
|
226
|
+
};
|
|
227
|
+
/** Result envelope returned by SkillsManager.requestMutation(). */
|
|
228
|
+
export type SkillMutationResult = {
|
|
229
|
+
decision: SkillMutationDecision;
|
|
230
|
+
/** The resulting skill after an applied create/update (absent for delete/pending/rejected). */
|
|
231
|
+
skill?: SkillDefinition;
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* Instance-level skills configuration (NeuroLink constructor `skills` option).
|
|
235
|
+
* Opt-in: nothing is registered or injected unless `enabled: true`.
|
|
236
|
+
*/
|
|
237
|
+
export type SkillsConfig = {
|
|
238
|
+
enabled: boolean;
|
|
239
|
+
/** Persistence backend. Default: `{ type: "memory" }`. */
|
|
240
|
+
storage?: SkillsStorageConfig;
|
|
241
|
+
/**
|
|
242
|
+
* Inject a compact skills index (names + descriptions, never instructions)
|
|
243
|
+
* into the system prompt of each generate()/stream() call. Default: true.
|
|
244
|
+
* Set false for curator-style pure tool-driven disclosure.
|
|
245
|
+
*/
|
|
246
|
+
promptIndex?: boolean;
|
|
247
|
+
/** Maximum skills hydrated (with instructions) per search. Default: 5. */
|
|
248
|
+
maxMatches?: number;
|
|
249
|
+
/** Maximum entries rendered in the prompt index before truncation. Default: 50. */
|
|
250
|
+
promptIndexMaxItems?: number;
|
|
251
|
+
/** Index cache TTL in milliseconds. Default: 30000. 0 disables caching. */
|
|
252
|
+
indexCacheTtlMs?: number;
|
|
253
|
+
/** Default scope filter applied when a call/tool provides none. */
|
|
254
|
+
defaultScopeId?: string;
|
|
255
|
+
/**
|
|
256
|
+
* Register skill_create / skill_update / skill_delete tools so the model
|
|
257
|
+
* can propose skill changes. Default: false. Combine with
|
|
258
|
+
* `onMutationRequest` to gate writes behind host approval.
|
|
259
|
+
*/
|
|
260
|
+
allowMutations?: boolean;
|
|
261
|
+
/**
|
|
262
|
+
* Host approval gate invoked before any mutation is applied. When absent
|
|
263
|
+
* and allowMutations is true, mutations apply directly. Errors thrown
|
|
264
|
+
* here reject the mutation (fail closed for writes).
|
|
265
|
+
*/
|
|
266
|
+
onMutationRequest?: (action: SkillMutationAction) => Promise<SkillMutationDecision>;
|
|
267
|
+
};
|
|
268
|
+
/**
|
|
269
|
+
* Structural view of SkillsManager consumed by the skill tools factory —
|
|
270
|
+
* keeps skillTools.ts decoupled from the concrete manager class.
|
|
271
|
+
*/
|
|
272
|
+
export type SkillsManagerLike = {
|
|
273
|
+
search: (query: SkillSearchQuery) => Promise<SkillDefinition[]>;
|
|
274
|
+
list: (scopeId?: string) => Promise<SkillIndexItem[]>;
|
|
275
|
+
requestMutation: (action: SkillMutationAction) => Promise<SkillMutationResult>;
|
|
276
|
+
};
|
|
277
|
+
/** Options for the createSkillTools factory. */
|
|
278
|
+
export type SkillToolsOptions = {
|
|
279
|
+
/** Include skill_create / skill_update / skill_delete. Default: false. */
|
|
280
|
+
allowMutations?: boolean;
|
|
281
|
+
};
|
|
282
|
+
/**
|
|
283
|
+
* Per-call skills control on generate()/stream(). Only effective when the
|
|
284
|
+
* instance was constructed with skills enabled; per-call wins over instance
|
|
285
|
+
* config (same precedence convention as per-call credentials).
|
|
286
|
+
*/
|
|
287
|
+
export type SkillsCallOptions = {
|
|
288
|
+
/** Master toggle for this call (prompt index only — tools stay registered). Default: true. */
|
|
289
|
+
enabled?: boolean;
|
|
290
|
+
/** Per-call override of SkillsConfig.promptIndex. */
|
|
291
|
+
promptIndex?: boolean;
|
|
292
|
+
/** Scope filter for the prompt index on this call. Overrides defaultScopeId. */
|
|
293
|
+
scopeId?: string;
|
|
294
|
+
/** Restrict the prompt index to skills carrying at least one of these tags. */
|
|
295
|
+
tags?: string[];
|
|
296
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native skills support — versioned, discoverable instruction packs
|
|
3
|
+
* (SOPs, playbooks, workflows) exposed to the model via progressive
|
|
4
|
+
* disclosure: a cheap name+description index up front, full instructions
|
|
5
|
+
* loaded on demand through built-in skill tools.
|
|
6
|
+
*
|
|
7
|
+
* Architecture mirrors the Hippocampus memory subsystem: a `skills` config
|
|
8
|
+
* on the NeuroLink constructor lazily initializes a SkillsManager, which
|
|
9
|
+
* auto-registers built-in tools (search_skills / list_skills, plus gated
|
|
10
|
+
* mutation tools) and optionally injects a compact skills index into the
|
|
11
|
+
* system prompt of each generate()/stream() call.
|
|
12
|
+
*
|
|
13
|
+
* Naming: every exported type carries a `Skill` prefix to satisfy the
|
|
14
|
+
* `unique-type-names` ESLint rule.
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=skills.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 { SkillsCallOptions } from "./skills.js";
|
|
4
5
|
import type { AnalyticsData, ToolExecutionEvent, ToolExecutionSummary } from "../types/index.js";
|
|
5
6
|
import type { MiddlewareFactoryOptions, OnChunkCallback, OnErrorCallback, OnFinishCallback } from "../types/middleware.js";
|
|
6
7
|
import type { TokenUsage } from "./analytics.js";
|
|
@@ -534,6 +535,13 @@ export type StreamOptions = {
|
|
|
534
535
|
};
|
|
535
536
|
/** @deprecated Use `piiDetection`, `responseValidation`, and `inputValidation` instead. */
|
|
536
537
|
processors?: ProcessorPipelineConfig;
|
|
538
|
+
/**
|
|
539
|
+
* Per-call skills control. Only effective when the instance was
|
|
540
|
+
* constructed with `skills.enabled: true`. Lets a call disable the
|
|
541
|
+
* prompt index, or narrow it by scope/tags. Per-call wins over
|
|
542
|
+
* instance config.
|
|
543
|
+
*/
|
|
544
|
+
skills?: SkillsCallOptions;
|
|
537
545
|
};
|
|
538
546
|
/**
|
|
539
547
|
* Stream function result type - Primary output format for streaming
|
package/dist/neurolink.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type { RedisConversationMemoryManager } from "./core/redisConversationMem
|
|
|
12
12
|
import { ExternalServerManager } from "./mcp/externalServerManager.js";
|
|
13
13
|
import { MCPToolRegistry } from "./mcp/toolRegistry.js";
|
|
14
14
|
import type { DynamicOptions } from "./types/index.js";
|
|
15
|
+
import { SkillsManager } from "./skills/skillsManager.js";
|
|
15
16
|
import { TaskManager } from "./tasks/taskManager.js";
|
|
16
17
|
/**
|
|
17
18
|
* Curator P2-4 dedup (concurrency-safe): native providers emit
|
|
@@ -140,6 +141,8 @@ export declare class NeuroLink {
|
|
|
140
141
|
private cachedFileTools;
|
|
141
142
|
private memoryInstance?;
|
|
142
143
|
private memorySDKConfig?;
|
|
144
|
+
private skillsManagerInstance?;
|
|
145
|
+
private skillsConfig?;
|
|
143
146
|
/**
|
|
144
147
|
* Extract and set Langfuse context from options with proper async scoping
|
|
145
148
|
*/
|
|
@@ -264,6 +267,31 @@ export declare class NeuroLink {
|
|
|
264
267
|
* Only registered when Redis conversation memory is active.
|
|
265
268
|
*/
|
|
266
269
|
private registerMemoryRetrievalTools;
|
|
270
|
+
/**
|
|
271
|
+
* Lazy initialization for the skills subsystem — mirrors ensureMemoryReady().
|
|
272
|
+
* Returns null (and stays null) when skills are not configured or the
|
|
273
|
+
* store failed to initialize; read paths fail open on that null.
|
|
274
|
+
*/
|
|
275
|
+
private ensureSkillsReady;
|
|
276
|
+
/**
|
|
277
|
+
* Register the built-in skill tools (search_skills / list_skills, plus
|
|
278
|
+
* mutation tools when allowMutations is set). Follows the
|
|
279
|
+
* registerMemoryRetrievalTools() pattern: registered via registerTool()
|
|
280
|
+
* so they land in the "user-defined" category that reaches the LLM tool
|
|
281
|
+
* schema, with the manager resolved lazily at execution time.
|
|
282
|
+
*/
|
|
283
|
+
private registerSkillTools;
|
|
284
|
+
/**
|
|
285
|
+
* Append the compact skills index (names + descriptions, never
|
|
286
|
+
* instructions) to the system prompt for one generate()/stream() call.
|
|
287
|
+
* Fails open: any error leaves the prompt untouched.
|
|
288
|
+
*/
|
|
289
|
+
private applySkillsPromptIndex;
|
|
290
|
+
/**
|
|
291
|
+
* Programmatic access to the skills subsystem (search/list/get/mutations).
|
|
292
|
+
* Returns null when skills are not configured or failed to initialize.
|
|
293
|
+
*/
|
|
294
|
+
getSkillsManager(): SkillsManager | null;
|
|
267
295
|
/** Format memory context for prompt inclusion */
|
|
268
296
|
private formatMemoryContext;
|
|
269
297
|
/**
|
package/dist/neurolink.js
CHANGED
|
@@ -54,6 +54,8 @@ import { MCPToolRegistry } from "./mcp/toolRegistry.js";
|
|
|
54
54
|
import { resolveDynamicArgument } from "./dynamic/dynamicResolver.js";
|
|
55
55
|
import { initializeHippocampus } from "./memory/hippocampusInitializer.js";
|
|
56
56
|
import { createMemoryRetrievalTools } from "./memory/memoryRetrievalTools.js";
|
|
57
|
+
import { SkillsManager } from "./skills/skillsManager.js";
|
|
58
|
+
import { createSkillTools } from "./skills/skillTools.js";
|
|
57
59
|
import { getMetricsAggregator, MetricsAggregator, } from "./observability/metricsAggregator.js";
|
|
58
60
|
import { SpanStatus, SpanType, CircuitBreakerOpenError, ConversationMemoryError, ModelAccessDeniedError, } from "./types/index.js";
|
|
59
61
|
import { SpanSerializer } from "./observability/utils/spanSerializer.js";
|
|
@@ -458,6 +460,10 @@ export class NeuroLink {
|
|
|
458
460
|
// Memory instance and config
|
|
459
461
|
memoryInstance;
|
|
460
462
|
memorySDKConfig;
|
|
463
|
+
// Skills subsystem — lazily initialized manager + instance config.
|
|
464
|
+
// `undefined` = not yet attempted, `null` = init failed (stay disabled).
|
|
465
|
+
skillsManagerInstance;
|
|
466
|
+
skillsConfig;
|
|
461
467
|
/**
|
|
462
468
|
* Extract and set Langfuse context from options with proper async scoping
|
|
463
469
|
*/
|
|
@@ -830,6 +836,10 @@ export class NeuroLink {
|
|
|
830
836
|
this.initializeMCPEnhancements(config);
|
|
831
837
|
this.registerFileTools();
|
|
832
838
|
this.registerMemoryRetrievalTools();
|
|
839
|
+
if (config?.skills?.enabled) {
|
|
840
|
+
this.skillsConfig = config.skills;
|
|
841
|
+
this.registerSkillTools();
|
|
842
|
+
}
|
|
833
843
|
this.initializeLangfuse(constructorId, constructorStartTime, constructorHrTimeStart);
|
|
834
844
|
this.initializeMetricsListeners();
|
|
835
845
|
this.logConstructorComplete(constructorId, constructorStartTime, constructorHrTimeStart);
|
|
@@ -1243,6 +1253,107 @@ export class NeuroLink {
|
|
|
1243
1253
|
});
|
|
1244
1254
|
logger.info("[NeuroLink] Memory retrieval tools registered");
|
|
1245
1255
|
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Lazy initialization for the skills subsystem — mirrors ensureMemoryReady().
|
|
1258
|
+
* Returns null (and stays null) when skills are not configured or the
|
|
1259
|
+
* store failed to initialize; read paths fail open on that null.
|
|
1260
|
+
*/
|
|
1261
|
+
ensureSkillsReady() {
|
|
1262
|
+
if (this.skillsManagerInstance !== undefined) {
|
|
1263
|
+
return this.skillsManagerInstance;
|
|
1264
|
+
}
|
|
1265
|
+
if (!this.skillsConfig?.enabled) {
|
|
1266
|
+
this.skillsManagerInstance = null;
|
|
1267
|
+
return null;
|
|
1268
|
+
}
|
|
1269
|
+
try {
|
|
1270
|
+
this.skillsManagerInstance = new SkillsManager(this.skillsConfig);
|
|
1271
|
+
}
|
|
1272
|
+
catch (error) {
|
|
1273
|
+
logger.warn("[NeuroLink] Skills initialization failed — skills disabled for this instance", { error: error instanceof Error ? error.message : String(error) });
|
|
1274
|
+
this.skillsManagerInstance = null;
|
|
1275
|
+
}
|
|
1276
|
+
return this.skillsManagerInstance;
|
|
1277
|
+
}
|
|
1278
|
+
/**
|
|
1279
|
+
* Register the built-in skill tools (search_skills / list_skills, plus
|
|
1280
|
+
* mutation tools when allowMutations is set). Follows the
|
|
1281
|
+
* registerMemoryRetrievalTools() pattern: registered via registerTool()
|
|
1282
|
+
* so they land in the "user-defined" category that reaches the LLM tool
|
|
1283
|
+
* schema, with the manager resolved lazily at execution time.
|
|
1284
|
+
*/
|
|
1285
|
+
registerSkillTools() {
|
|
1286
|
+
const canonicalTools = createSkillTools(() => this.ensureSkillsReady(), {
|
|
1287
|
+
allowMutations: this.skillsConfig?.allowMutations === true,
|
|
1288
|
+
});
|
|
1289
|
+
for (const [toolName, toolDef] of Object.entries(canonicalTools)) {
|
|
1290
|
+
this.registerTool(toolName, {
|
|
1291
|
+
name: toolName,
|
|
1292
|
+
description: toolDef.description ?? toolName,
|
|
1293
|
+
// Zod schema — registerTool() detects isZodSchema and preserves it
|
|
1294
|
+
// so ToolsManager gives the LLM full parameter types.
|
|
1295
|
+
inputSchema: toolDef
|
|
1296
|
+
.inputSchema,
|
|
1297
|
+
execute: async (params) => withTimeout(toolDef.execute(params, { toolCallId: "skill-tool", messages: [] }), TOOL_TIMEOUTS.EXECUTION_DEFAULT_MS, ErrorFactory.toolTimeout(toolName, TOOL_TIMEOUTS.EXECUTION_DEFAULT_MS)),
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
logger.info(`[NeuroLink] Registered ${Object.keys(canonicalTools).length} skill tools`, { allowMutations: this.skillsConfig?.allowMutations === true });
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* Append the compact skills index (names + descriptions, never
|
|
1304
|
+
* instructions) to the system prompt for one generate()/stream() call.
|
|
1305
|
+
* Fails open: any error leaves the prompt untouched.
|
|
1306
|
+
*/
|
|
1307
|
+
async applySkillsPromptIndex(options) {
|
|
1308
|
+
if (!this.skillsConfig?.enabled || options.skills?.enabled === false) {
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1311
|
+
// Per-call promptIndex wins over instance config; default is on.
|
|
1312
|
+
const promptIndexEnabled = options.skills?.promptIndex ?? this.skillsConfig.promptIndex ?? true;
|
|
1313
|
+
if (!promptIndexEnabled) {
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
// Media-only modes have no meaningful text prompt to augment.
|
|
1317
|
+
const mode = options.output?.mode;
|
|
1318
|
+
if (mode === "avatar" ||
|
|
1319
|
+
mode === "music" ||
|
|
1320
|
+
mode === "video" ||
|
|
1321
|
+
mode === "ppt") {
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
try {
|
|
1325
|
+
const manager = this.ensureSkillsReady();
|
|
1326
|
+
if (!manager) {
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
const block = await manager.buildPromptIndex({
|
|
1330
|
+
...(options.skills?.scopeId !== undefined
|
|
1331
|
+
? { scopeId: options.skills.scopeId }
|
|
1332
|
+
: {}),
|
|
1333
|
+
...(options.skills?.tags !== undefined
|
|
1334
|
+
? { tags: options.skills.tags }
|
|
1335
|
+
: {}),
|
|
1336
|
+
});
|
|
1337
|
+
if (block) {
|
|
1338
|
+
options.systemPrompt = options.systemPrompt
|
|
1339
|
+
? `${options.systemPrompt}\n\n${block}`
|
|
1340
|
+
: block;
|
|
1341
|
+
logger.debug("[NeuroLink] Skills prompt index injected", {
|
|
1342
|
+
blockLength: block.length,
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
catch (error) {
|
|
1347
|
+
logger.warn("[NeuroLink] Skills prompt index injection failed — continuing without it", { error: error instanceof Error ? error.message : String(error) });
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
/**
|
|
1351
|
+
* Programmatic access to the skills subsystem (search/list/get/mutations).
|
|
1352
|
+
* Returns null when skills are not configured or failed to initialize.
|
|
1353
|
+
*/
|
|
1354
|
+
getSkillsManager() {
|
|
1355
|
+
return this.ensureSkillsReady();
|
|
1356
|
+
}
|
|
1246
1357
|
/** Format memory context for prompt inclusion */
|
|
1247
1358
|
formatMemoryContext(memoryContext, currentInput) {
|
|
1248
1359
|
return `Context from previous conversations:
|
|
@@ -3499,6 +3610,9 @@ Current user's request: ${currentInput}`;
|
|
|
3499
3610
|
});
|
|
3500
3611
|
}
|
|
3501
3612
|
}
|
|
3613
|
+
// Skills: append the compact skills index to the system prompt so the
|
|
3614
|
+
// model knows which skills exist (bodies load via search_skills).
|
|
3615
|
+
await this.applySkillsPromptIndex(options);
|
|
3502
3616
|
// Media-only modes (avatar, music, video, ppt) do not have a meaningful
|
|
3503
3617
|
// text prompt to augment with memory — skip injection to avoid corrupting
|
|
3504
3618
|
// the empty/synthesized input.text that was set for these modes.
|
|
@@ -7037,6 +7151,9 @@ Current user's request: ${currentInput}`;
|
|
|
7037
7151
|
logger.warn("Memory retrieval failed:", error);
|
|
7038
7152
|
}
|
|
7039
7153
|
}
|
|
7154
|
+
// Skills: append the compact skills index to the system prompt so the
|
|
7155
|
+
// model knows which skills exist (bodies load via search_skills).
|
|
7156
|
+
await this.applySkillsPromptIndex(options);
|
|
7040
7157
|
// Apply orchestration if enabled and no specific provider/model requested
|
|
7041
7158
|
if (this.enableOrchestration && !options.provider && !options.model) {
|
|
7042
7159
|
try {
|