@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
|
@@ -117,6 +117,12 @@ export declare class CLICommandFactory {
|
|
|
117
117
|
* Create memory commands
|
|
118
118
|
*/
|
|
119
119
|
static createMemoryCommands(): CommandModule;
|
|
120
|
+
/**
|
|
121
|
+
* Create skills commands — manage the local skills store
|
|
122
|
+
* (list / show / search / create / delete). The store directory comes
|
|
123
|
+
* from --skills-dir, NEUROLINK_SKILLS_DIR, or defaults to ./skills.
|
|
124
|
+
*/
|
|
125
|
+
static createSkillsCommands(): CommandModule;
|
|
120
126
|
/**
|
|
121
127
|
* Create config commands
|
|
122
128
|
*/
|
|
@@ -235,6 +241,17 @@ export declare class CLICommandFactory {
|
|
|
235
241
|
/**
|
|
236
242
|
* Execute memory stats command
|
|
237
243
|
*/
|
|
244
|
+
/**
|
|
245
|
+
* Resolve a standalone SkillsManager for the `skills` command group.
|
|
246
|
+
* Directory precedence: --skills-dir > NEUROLINK_SKILLS_DIR > ./skills.
|
|
247
|
+
* Cache is disabled so every command sees the directory's current state.
|
|
248
|
+
*/
|
|
249
|
+
private static resolveSkillsManagerForCli;
|
|
250
|
+
private static executeSkillsList;
|
|
251
|
+
private static executeSkillsShow;
|
|
252
|
+
private static executeSkillsSearch;
|
|
253
|
+
private static executeSkillsCreate;
|
|
254
|
+
private static executeSkillsDelete;
|
|
238
255
|
private static executeMemoryStats;
|
|
239
256
|
/**
|
|
240
257
|
* Execute memory history command
|
|
@@ -12,6 +12,8 @@ import { logger } from "../../lib/utils/logger.js";
|
|
|
12
12
|
import { createThinkingConfigFromRecord } from "../../lib/utils/thinkingConfig.js";
|
|
13
13
|
import { buildToolRoutingConfigFromCli } from "../utils/toolRoutingFlags.js";
|
|
14
14
|
import { buildClassifierRouterConfigFromCli } from "../utils/classifierRouterFlags.js";
|
|
15
|
+
import { buildSkillsConfigFromCli } from "../utils/skillsFlags.js";
|
|
16
|
+
import { SkillsManager } from "../../lib/skills/skillsManager.js";
|
|
15
17
|
import { configManager } from "../commands/config.js";
|
|
16
18
|
import { MCPCommandFactory } from "../commands/mcp.js";
|
|
17
19
|
import { ModelsCommandFactory } from "../commands/models.js";
|
|
@@ -711,6 +713,14 @@ export class CLICommandFactory {
|
|
|
711
713
|
description: "Minimum response length (characters)",
|
|
712
714
|
alias: "output-min-length",
|
|
713
715
|
},
|
|
716
|
+
// Skills options
|
|
717
|
+
skillsDir: {
|
|
718
|
+
type: "string",
|
|
719
|
+
description: "Directory of skills (SOPs/playbooks) to make available to the AI. " +
|
|
720
|
+
"Supports <id>.json, <name>.md, and <name>/SKILL.md layouts. " +
|
|
721
|
+
"Also settable via NEUROLINK_SKILLS_DIR.",
|
|
722
|
+
alias: "skills-dir",
|
|
723
|
+
},
|
|
714
724
|
};
|
|
715
725
|
// Helper method to build options for commands
|
|
716
726
|
static buildOptions(yargs, additionalOptions = {}) {
|
|
@@ -963,6 +973,8 @@ export class CLICommandFactory {
|
|
|
963
973
|
classifierModelRegion: argv.classifierModelRegion,
|
|
964
974
|
classifierPool: argv.classifierPool,
|
|
965
975
|
classifierTimeout: argv.classifierTimeout,
|
|
976
|
+
// Skills flag — constructor-level config (see note above).
|
|
977
|
+
skillsDir: argv.skillsDir,
|
|
966
978
|
};
|
|
967
979
|
}
|
|
968
980
|
/**
|
|
@@ -1651,6 +1663,77 @@ export class CLICommandFactory {
|
|
|
1651
1663
|
handler: () => { }, // No-op handler as subcommands handle everything
|
|
1652
1664
|
};
|
|
1653
1665
|
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Create skills commands — manage the local skills store
|
|
1668
|
+
* (list / show / search / create / delete). The store directory comes
|
|
1669
|
+
* from --skills-dir, NEUROLINK_SKILLS_DIR, or defaults to ./skills.
|
|
1670
|
+
*/
|
|
1671
|
+
static createSkillsCommands() {
|
|
1672
|
+
return {
|
|
1673
|
+
command: "skills <subcommand>",
|
|
1674
|
+
describe: "Manage skills (SOPs/playbooks the AI can follow)",
|
|
1675
|
+
builder: (yargs) => {
|
|
1676
|
+
return yargs
|
|
1677
|
+
.command("list", "List all active skills (index only, no instructions)", (y) => CLICommandFactory.buildOptions(y)
|
|
1678
|
+
.example("$0 skills list --skills-dir ./skills", "List skills")
|
|
1679
|
+
.example("$0 skills list --format json", "Export as JSON"), async (argv) => await CLICommandFactory.executeSkillsList(argv))
|
|
1680
|
+
.command("show <skill>", "Show one skill including its full instructions", (y) => CLICommandFactory.buildOptions(y)
|
|
1681
|
+
.positional("skill", {
|
|
1682
|
+
type: "string",
|
|
1683
|
+
description: "Skill id or exact name",
|
|
1684
|
+
demandOption: true,
|
|
1685
|
+
})
|
|
1686
|
+
.example("$0 skills show refund_dispute_escalation", "Show a skill by name"), async (argv) => await CLICommandFactory.executeSkillsShow(argv))
|
|
1687
|
+
.command("search <query>", "Search skills by keyword (matches name and description)", (y) => CLICommandFactory.buildOptions(y)
|
|
1688
|
+
.positional("query", {
|
|
1689
|
+
type: "string",
|
|
1690
|
+
description: "Keyword to match",
|
|
1691
|
+
demandOption: true,
|
|
1692
|
+
})
|
|
1693
|
+
.option("tag", {
|
|
1694
|
+
type: "string",
|
|
1695
|
+
description: "Tag filter applied on top of the keyword",
|
|
1696
|
+
})
|
|
1697
|
+
.example('$0 skills search "refund"', "Find refund skills"), async (argv) => await CLICommandFactory.executeSkillsSearch(argv))
|
|
1698
|
+
.command("create", "Create a new skill in the store", (y) => CLICommandFactory.buildOptions(y)
|
|
1699
|
+
.option("name", {
|
|
1700
|
+
type: "string",
|
|
1701
|
+
description: "Machine-friendly unique name (snake_case)",
|
|
1702
|
+
demandOption: true,
|
|
1703
|
+
})
|
|
1704
|
+
.option("description", {
|
|
1705
|
+
type: "string",
|
|
1706
|
+
description: "When this skill applies (used for matching)",
|
|
1707
|
+
demandOption: true,
|
|
1708
|
+
})
|
|
1709
|
+
.option("instructions", {
|
|
1710
|
+
type: "string",
|
|
1711
|
+
description: "Full instructions text",
|
|
1712
|
+
})
|
|
1713
|
+
.option("instructions-file", {
|
|
1714
|
+
type: "string",
|
|
1715
|
+
description: "Read instructions from a file",
|
|
1716
|
+
})
|
|
1717
|
+
.option("display-name", {
|
|
1718
|
+
type: "string",
|
|
1719
|
+
description: "Human-readable display name",
|
|
1720
|
+
})
|
|
1721
|
+
.option("tags", {
|
|
1722
|
+
type: "array",
|
|
1723
|
+
string: true,
|
|
1724
|
+
description: "Domain tags",
|
|
1725
|
+
})
|
|
1726
|
+
.example('$0 skills create --name deploy_sop --description "How to deploy" --instructions-file ./sop.md', "Create from a file"), async (argv) => await CLICommandFactory.executeSkillsCreate(argv))
|
|
1727
|
+
.command("delete <skill>", "Soft-delete (deprecate) a skill", (y) => CLICommandFactory.buildOptions(y).positional("skill", {
|
|
1728
|
+
type: "string",
|
|
1729
|
+
description: "Skill id or exact name",
|
|
1730
|
+
demandOption: true,
|
|
1731
|
+
}), async (argv) => await CLICommandFactory.executeSkillsDelete(argv))
|
|
1732
|
+
.demandCommand(1, "Please specify a skills subcommand");
|
|
1733
|
+
},
|
|
1734
|
+
handler: () => { }, // No-op handler as subcommands handle everything
|
|
1735
|
+
};
|
|
1736
|
+
}
|
|
1654
1737
|
/**
|
|
1655
1738
|
* Create config commands
|
|
1656
1739
|
*/
|
|
@@ -1900,6 +1983,12 @@ export class CLICommandFactory {
|
|
|
1900
1983
|
},
|
|
1901
1984
|
};
|
|
1902
1985
|
}
|
|
1986
|
+
// Inject skills config (--skills-dir / NEUROLINK_SKILLS_DIR) before
|
|
1987
|
+
// the loop session constructs its NeuroLink instance.
|
|
1988
|
+
const loopSkillsConfig = buildSkillsConfigFromCli(argv);
|
|
1989
|
+
if (loopSkillsConfig) {
|
|
1990
|
+
globalSession.setSkillsConfig(loopSkillsConfig);
|
|
1991
|
+
}
|
|
1903
1992
|
// Handle --list-conversations option
|
|
1904
1993
|
if (listConversations) {
|
|
1905
1994
|
const { ConversationSelector } = await import("../loop/conversationSelector.js");
|
|
@@ -2399,6 +2488,11 @@ export class CLICommandFactory {
|
|
|
2399
2488
|
if (classifierRouterConfig) {
|
|
2400
2489
|
globalSession.setClassifierRouterConfig(classifierRouterConfig);
|
|
2401
2490
|
}
|
|
2491
|
+
// Inject skills config (--skills-dir / NEUROLINK_SKILLS_DIR) before SDK construction.
|
|
2492
|
+
const skillsConfig = buildSkillsConfigFromCli(options);
|
|
2493
|
+
if (skillsConfig) {
|
|
2494
|
+
globalSession.setSkillsConfig(skillsConfig);
|
|
2495
|
+
}
|
|
2402
2496
|
// Initialize SDK and session
|
|
2403
2497
|
const sdk = globalSession.getOrCreateNeuroLink();
|
|
2404
2498
|
const sessionVariables = CLICommandFactory.normalizeLoopSessionVariables(globalSession.getSessionVariables());
|
|
@@ -2667,6 +2761,11 @@ export class CLICommandFactory {
|
|
|
2667
2761
|
if (classifierRouterConfig) {
|
|
2668
2762
|
globalSession.setClassifierRouterConfig(classifierRouterConfig);
|
|
2669
2763
|
}
|
|
2764
|
+
// Inject skills config (--skills-dir / NEUROLINK_SKILLS_DIR) before SDK construction.
|
|
2765
|
+
const skillsConfig = buildSkillsConfigFromCli(options);
|
|
2766
|
+
if (skillsConfig) {
|
|
2767
|
+
globalSession.setSkillsConfig(skillsConfig);
|
|
2768
|
+
}
|
|
2670
2769
|
const sdk = globalSession.getOrCreateNeuroLink();
|
|
2671
2770
|
const sessionVariables = CLICommandFactory.normalizeLoopSessionVariables(globalSession.getSessionVariables());
|
|
2672
2771
|
const enhancedOptions = { ...options, ...sessionVariables };
|
|
@@ -3182,6 +3281,11 @@ export class CLICommandFactory {
|
|
|
3182
3281
|
if (classifierRouterConfig) {
|
|
3183
3282
|
globalSession.setClassifierRouterConfig(classifierRouterConfig);
|
|
3184
3283
|
}
|
|
3284
|
+
// Inject skills config (--skills-dir / NEUROLINK_SKILLS_DIR) before SDK construction.
|
|
3285
|
+
const skillsConfig = buildSkillsConfigFromCli(options);
|
|
3286
|
+
if (skillsConfig) {
|
|
3287
|
+
globalSession.setSkillsConfig(skillsConfig);
|
|
3288
|
+
}
|
|
3185
3289
|
const sdk = globalSession.getOrCreateNeuroLink();
|
|
3186
3290
|
const sessionVariables = CLICommandFactory.normalizeLoopSessionVariables(globalSession.getSessionVariables());
|
|
3187
3291
|
const enhancedOptions = { ...options, ...sessionVariables };
|
|
@@ -3339,6 +3443,156 @@ export class CLICommandFactory {
|
|
|
3339
3443
|
/**
|
|
3340
3444
|
* Execute memory stats command
|
|
3341
3445
|
*/
|
|
3446
|
+
/**
|
|
3447
|
+
* Resolve a standalone SkillsManager for the `skills` command group.
|
|
3448
|
+
* Directory precedence: --skills-dir > NEUROLINK_SKILLS_DIR > ./skills.
|
|
3449
|
+
* Cache is disabled so every command sees the directory's current state.
|
|
3450
|
+
*/
|
|
3451
|
+
static resolveSkillsManagerForCli(argv) {
|
|
3452
|
+
const raw = argv.skillsDir;
|
|
3453
|
+
const dir = (typeof raw === "string" && raw.trim()) ||
|
|
3454
|
+
process.env.NEUROLINK_SKILLS_DIR?.trim() ||
|
|
3455
|
+
"./skills";
|
|
3456
|
+
return new SkillsManager({
|
|
3457
|
+
enabled: true,
|
|
3458
|
+
storage: { type: "filesystem", path: dir },
|
|
3459
|
+
indexCacheTtlMs: 0,
|
|
3460
|
+
});
|
|
3461
|
+
}
|
|
3462
|
+
static async executeSkillsList(argv) {
|
|
3463
|
+
const options = CLICommandFactory.processOptions(argv);
|
|
3464
|
+
try {
|
|
3465
|
+
const manager = CLICommandFactory.resolveSkillsManagerForCli(argv);
|
|
3466
|
+
const skills = await manager.list();
|
|
3467
|
+
if (options.format === "json") {
|
|
3468
|
+
CLICommandFactory.handleOutput({ skills, count: skills.length }, options);
|
|
3469
|
+
return;
|
|
3470
|
+
}
|
|
3471
|
+
if (skills.length === 0) {
|
|
3472
|
+
logger.always(chalk.yellow("No active skills found."));
|
|
3473
|
+
return;
|
|
3474
|
+
}
|
|
3475
|
+
logger.always(chalk.blue(`🧩 Skills (${skills.length}):`));
|
|
3476
|
+
for (const skill of skills) {
|
|
3477
|
+
const tags = skill.tags?.length ? ` [${skill.tags.join(", ")}]` : "";
|
|
3478
|
+
logger.always(` ${chalk.bold(skill.name)} — ${skill.description}${tags}`);
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
catch (error) {
|
|
3482
|
+
handleError(error, "Skills list");
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3485
|
+
static async executeSkillsShow(argv) {
|
|
3486
|
+
const options = CLICommandFactory.processOptions(argv);
|
|
3487
|
+
try {
|
|
3488
|
+
const manager = CLICommandFactory.resolveSkillsManagerForCli(argv);
|
|
3489
|
+
const skill = await manager.get(argv.skill);
|
|
3490
|
+
if (!skill) {
|
|
3491
|
+
logger.always(chalk.yellow(`Skill "${argv.skill}" not found.`));
|
|
3492
|
+
process.exitCode = 1;
|
|
3493
|
+
return;
|
|
3494
|
+
}
|
|
3495
|
+
if (options.format === "json") {
|
|
3496
|
+
CLICommandFactory.handleOutput(skill, options);
|
|
3497
|
+
return;
|
|
3498
|
+
}
|
|
3499
|
+
logger.always(chalk.blue(`🧩 ${skill.displayName || skill.name}`));
|
|
3500
|
+
logger.always(` id: ${skill.id} version: ${skill.version ?? 1}`);
|
|
3501
|
+
logger.always(` ${skill.description}`);
|
|
3502
|
+
if (skill.tags?.length) {
|
|
3503
|
+
logger.always(` tags: ${skill.tags.join(", ")}`);
|
|
3504
|
+
}
|
|
3505
|
+
logger.always("");
|
|
3506
|
+
logger.always(skill.instructions);
|
|
3507
|
+
}
|
|
3508
|
+
catch (error) {
|
|
3509
|
+
handleError(error, "Skills show");
|
|
3510
|
+
}
|
|
3511
|
+
}
|
|
3512
|
+
static async executeSkillsSearch(argv) {
|
|
3513
|
+
const options = CLICommandFactory.processOptions(argv);
|
|
3514
|
+
try {
|
|
3515
|
+
const manager = CLICommandFactory.resolveSkillsManagerForCli(argv);
|
|
3516
|
+
const matches = await manager.search({
|
|
3517
|
+
query: argv.query,
|
|
3518
|
+
...(argv.tag ? { tag: argv.tag } : {}),
|
|
3519
|
+
});
|
|
3520
|
+
if (options.format === "json") {
|
|
3521
|
+
CLICommandFactory.handleOutput({ skills: matches, count: matches.length }, options);
|
|
3522
|
+
return;
|
|
3523
|
+
}
|
|
3524
|
+
if (matches.length === 0) {
|
|
3525
|
+
logger.always(chalk.yellow(`No skills match "${argv.query}".`));
|
|
3526
|
+
return;
|
|
3527
|
+
}
|
|
3528
|
+
logger.always(chalk.blue(`🔎 ${matches.length} match(es):`));
|
|
3529
|
+
for (const skill of matches) {
|
|
3530
|
+
logger.always(` ${chalk.bold(skill.name)} — ${skill.description}`);
|
|
3531
|
+
}
|
|
3532
|
+
logger.always("");
|
|
3533
|
+
logger.always("Use `neurolink skills show <name>` for full instructions.");
|
|
3534
|
+
}
|
|
3535
|
+
catch (error) {
|
|
3536
|
+
handleError(error, "Skills search");
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
static async executeSkillsCreate(argv) {
|
|
3540
|
+
const options = CLICommandFactory.processOptions(argv);
|
|
3541
|
+
try {
|
|
3542
|
+
let instructions = argv.instructions;
|
|
3543
|
+
if (!instructions && argv.instructionsFile) {
|
|
3544
|
+
instructions = fs.readFileSync(argv.instructionsFile, "utf-8");
|
|
3545
|
+
}
|
|
3546
|
+
if (!instructions?.trim()) {
|
|
3547
|
+
logger.always(chalk.red("Provide skill instructions via --instructions or --instructions-file."));
|
|
3548
|
+
process.exitCode = 1;
|
|
3549
|
+
return;
|
|
3550
|
+
}
|
|
3551
|
+
const manager = CLICommandFactory.resolveSkillsManagerForCli(argv);
|
|
3552
|
+
const result = await manager.requestMutation({
|
|
3553
|
+
type: "create",
|
|
3554
|
+
skill: {
|
|
3555
|
+
name: argv.name,
|
|
3556
|
+
description: argv.description,
|
|
3557
|
+
instructions,
|
|
3558
|
+
...(argv.displayName ? { displayName: argv.displayName } : {}),
|
|
3559
|
+
...(argv.tags?.length ? { tags: argv.tags.map(String) } : {}),
|
|
3560
|
+
},
|
|
3561
|
+
});
|
|
3562
|
+
if (options.format === "json") {
|
|
3563
|
+
CLICommandFactory.handleOutput(result, options);
|
|
3564
|
+
return;
|
|
3565
|
+
}
|
|
3566
|
+
logger.always(chalk.green(`✅ Skill "${argv.name}" created (id: ${result.skill?.id}).`));
|
|
3567
|
+
}
|
|
3568
|
+
catch (error) {
|
|
3569
|
+
handleError(error, "Skills create");
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
static async executeSkillsDelete(argv) {
|
|
3573
|
+
const options = CLICommandFactory.processOptions(argv);
|
|
3574
|
+
try {
|
|
3575
|
+
const manager = CLICommandFactory.resolveSkillsManagerForCli(argv);
|
|
3576
|
+
const existing = await manager.get(argv.skill);
|
|
3577
|
+
if (!existing) {
|
|
3578
|
+
logger.always(chalk.yellow(`Skill "${argv.skill}" not found.`));
|
|
3579
|
+
process.exitCode = 1;
|
|
3580
|
+
return;
|
|
3581
|
+
}
|
|
3582
|
+
const result = await manager.requestMutation({
|
|
3583
|
+
type: "delete",
|
|
3584
|
+
skillId: existing.id,
|
|
3585
|
+
});
|
|
3586
|
+
if (options.format === "json") {
|
|
3587
|
+
CLICommandFactory.handleOutput(result, options);
|
|
3588
|
+
return;
|
|
3589
|
+
}
|
|
3590
|
+
logger.always(chalk.green(`✅ Skill "${existing.name}" deprecated (soft-deleted).`));
|
|
3591
|
+
}
|
|
3592
|
+
catch (error) {
|
|
3593
|
+
handleError(error, "Skills delete");
|
|
3594
|
+
}
|
|
3595
|
+
}
|
|
3342
3596
|
static async executeMemoryStats(argv) {
|
|
3343
3597
|
const options = CLICommandFactory.processOptions(argv);
|
|
3344
3598
|
const spinner = options.quiet
|
package/dist/cli/parser.js
CHANGED
|
@@ -161,6 +161,8 @@ export function initializeCliParser() {
|
|
|
161
161
|
.command(CLICommandFactory.createConfigCommands())
|
|
162
162
|
// Memory Command Group - Using CLICommandFactory
|
|
163
163
|
.command(CLICommandFactory.createMemoryCommands())
|
|
164
|
+
// Skills Command Group - Using CLICommandFactory
|
|
165
|
+
.command(CLICommandFactory.createSkillsCommands())
|
|
164
166
|
// Get Best Provider Command - Using CLICommandFactory
|
|
165
167
|
.command(CLICommandFactory.createBestProviderCommand())
|
|
166
168
|
// Validate Command (alias for config validate)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI → SkillsConfig mapping, following the toolRoutingFlags /
|
|
3
|
+
* classifierRouterFlags pattern.
|
|
4
|
+
*
|
|
5
|
+
* `--skills-dir <path>` (or NEUROLINK_SKILLS_DIR) enables skills with a
|
|
6
|
+
* filesystem store for generate / stream / batch / loop runs. Returns null
|
|
7
|
+
* when neither is provided so the SDK stays skills-free by default.
|
|
8
|
+
*/
|
|
9
|
+
import type { SkillsConfig } from "../../lib/types/index.js";
|
|
10
|
+
export declare function buildSkillsConfigFromCli(options: Record<string, unknown>): SkillsConfig | null;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI → SkillsConfig mapping, following the toolRoutingFlags /
|
|
3
|
+
* classifierRouterFlags pattern.
|
|
4
|
+
*
|
|
5
|
+
* `--skills-dir <path>` (or NEUROLINK_SKILLS_DIR) enables skills with a
|
|
6
|
+
* filesystem store for generate / stream / batch / loop runs. Returns null
|
|
7
|
+
* when neither is provided so the SDK stays skills-free by default.
|
|
8
|
+
*/
|
|
9
|
+
export function buildSkillsConfigFromCli(options) {
|
|
10
|
+
const dir = (typeof options.skillsDir === "string" && options.skillsDir.trim()) ||
|
|
11
|
+
(typeof process.env.NEUROLINK_SKILLS_DIR === "string" &&
|
|
12
|
+
process.env.NEUROLINK_SKILLS_DIR.trim()) ||
|
|
13
|
+
"";
|
|
14
|
+
if (!dir) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
enabled: true,
|
|
19
|
+
storage: { type: "filesystem", path: dir },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=skillsFlags.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -44,6 +44,11 @@ export { ErrorCode as ClientErrorCode, NeuroLinkError as ClientNeuroLinkError, H
|
|
|
44
44
|
export { AIProviderName, BedrockModels, OpenAIModels, VertexModels, } from "./constants/enums.js";
|
|
45
45
|
export { dynamicModelProvider } from "./core/dynamicModels.js";
|
|
46
46
|
export { validateTool } from "./sdk/toolRegistration.js";
|
|
47
|
+
export { SkillsManager } from "./skills/skillsManager.js";
|
|
48
|
+
export { createSkillStore, FileSystemSkillStore, InMemorySkillStore, } from "./skills/skillStores.js";
|
|
49
|
+
export { S3SkillStore } from "./skills/skillStoreS3.js";
|
|
50
|
+
export { RedisSkillStore } from "./skills/skillStoreRedis.js";
|
|
51
|
+
export { createSkillTools } from "./skills/skillTools.js";
|
|
47
52
|
export * from "./types/index.js";
|
|
48
53
|
export { isAbortError } from "./utils/errorHandling.js";
|
|
49
54
|
export { calculateCost, hasPricing } from "./utils/pricing.js";
|
package/dist/index.js
CHANGED
|
@@ -68,6 +68,12 @@ export { AIProviderName, BedrockModels, OpenAIModels, VertexModels, } from "./co
|
|
|
68
68
|
export { dynamicModelProvider } from "./core/dynamicModels.js";
|
|
69
69
|
// Tool Registration utility
|
|
70
70
|
export { validateTool } from "./sdk/toolRegistration.js";
|
|
71
|
+
// Skills subsystem — manager, stores, and the built-in tool factory
|
|
72
|
+
export { SkillsManager } from "./skills/skillsManager.js";
|
|
73
|
+
export { createSkillStore, FileSystemSkillStore, InMemorySkillStore, } from "./skills/skillStores.js";
|
|
74
|
+
export { S3SkillStore } from "./skills/skillStoreS3.js";
|
|
75
|
+
export { RedisSkillStore } from "./skills/skillStoreRedis.js";
|
|
76
|
+
export { createSkillTools } from "./skills/skillTools.js";
|
|
71
77
|
// Export ALL types from the centralized type barrel
|
|
72
78
|
export * from "./types/index.js";
|
|
73
79
|
// Error utilities
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -44,6 +44,11 @@ export { ErrorCode as ClientErrorCode, NeuroLinkError as ClientNeuroLinkError, H
|
|
|
44
44
|
export { AIProviderName, BedrockModels, OpenAIModels, VertexModels, } from "./constants/enums.js";
|
|
45
45
|
export { dynamicModelProvider } from "./core/dynamicModels.js";
|
|
46
46
|
export { validateTool } from "./sdk/toolRegistration.js";
|
|
47
|
+
export { SkillsManager } from "./skills/skillsManager.js";
|
|
48
|
+
export { createSkillStore, FileSystemSkillStore, InMemorySkillStore, } from "./skills/skillStores.js";
|
|
49
|
+
export { S3SkillStore } from "./skills/skillStoreS3.js";
|
|
50
|
+
export { RedisSkillStore } from "./skills/skillStoreRedis.js";
|
|
51
|
+
export { createSkillTools } from "./skills/skillTools.js";
|
|
47
52
|
export * from "./types/index.js";
|
|
48
53
|
export { isAbortError } from "./utils/errorHandling.js";
|
|
49
54
|
export { calculateCost, hasPricing } from "./utils/pricing.js";
|
package/dist/lib/index.js
CHANGED
|
@@ -68,6 +68,12 @@ export { AIProviderName, BedrockModels, OpenAIModels, VertexModels, } from "./co
|
|
|
68
68
|
export { dynamicModelProvider } from "./core/dynamicModels.js";
|
|
69
69
|
// Tool Registration utility
|
|
70
70
|
export { validateTool } from "./sdk/toolRegistration.js";
|
|
71
|
+
// Skills subsystem — manager, stores, and the built-in tool factory
|
|
72
|
+
export { SkillsManager } from "./skills/skillsManager.js";
|
|
73
|
+
export { createSkillStore, FileSystemSkillStore, InMemorySkillStore, } from "./skills/skillStores.js";
|
|
74
|
+
export { S3SkillStore } from "./skills/skillStoreS3.js";
|
|
75
|
+
export { RedisSkillStore } from "./skills/skillStoreRedis.js";
|
|
76
|
+
export { createSkillTools } from "./skills/skillTools.js";
|
|
71
77
|
// Export ALL types from the centralized type barrel
|
|
72
78
|
export * from "./types/index.js";
|
|
73
79
|
// Error utilities
|
package/dist/lib/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/lib/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 {
|