@kernel.chat/kbot 3.97.4 → 3.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/agent.js +22 -1
  2. package/dist/cli.js +163 -0
  3. package/dist/skills-loader.d.ts +37 -5
  4. package/dist/skills-loader.js +342 -50
  5. package/dist/teacher-logger.d.ts +71 -0
  6. package/dist/teacher-logger.js +162 -0
  7. package/dist/tools/idempotency-check.d.ts +2 -0
  8. package/dist/tools/idempotency-check.js +31 -0
  9. package/dist/tools/schedule-persistence.d.ts +2 -0
  10. package/dist/tools/schedule-persistence.js +19 -0
  11. package/dist/train-agent-trace.d.ts +29 -0
  12. package/dist/train-agent-trace.js +141 -0
  13. package/dist/train-curate.d.ts +25 -0
  14. package/dist/train-curate.js +354 -0
  15. package/dist/train-cycle.d.ts +22 -0
  16. package/dist/train-cycle.js +230 -0
  17. package/dist/train-grpo.d.ts +68 -0
  18. package/dist/train-grpo.js +206 -0
  19. package/dist/train-merge.d.ts +26 -0
  20. package/dist/train-merge.js +148 -0
  21. package/dist/train-self.d.ts +38 -0
  22. package/dist/train-self.js +232 -0
  23. package/package.json +2 -1
  24. package/skills/deployment/daemon-deployment/SKILL.md +70 -0
  25. package/skills/deployment/ship-pipeline/SKILL.md +81 -0
  26. package/skills/emergent/forge-reflex/SKILL.md +53 -0
  27. package/skills/emergent/mimic-hybrid/SKILL.md +56 -0
  28. package/skills/memory/dream-to-commit/SKILL.md +52 -0
  29. package/skills/memory/memory-cascade/SKILL.md +59 -0
  30. package/skills/music-production/ableton-session-build/SKILL.md +61 -0
  31. package/skills/orchestration/cross-agent-blackboard/SKILL.md +58 -0
  32. package/skills/orchestration/specialist-routing/SKILL.md +57 -0
  33. package/skills/self-improvement/autopoiesis-loop/SKILL.md +47 -0
  34. package/skills/self-improvement/skill-self-authorship/SKILL.md +70 -0
  35. package/skills/self-improvement/teacher-trace-curation/SKILL.md +54 -0
  36. package/skills/software-development/systematic-debugging/SKILL.md +86 -0
  37. package/skills/software-development/test-driven-development/SKILL.md +74 -0
package/dist/agent.js CHANGED
@@ -654,6 +654,19 @@ function isComplexTask(message) {
654
654
  async function callProvider(provider, apiKey, model, systemContext, messages, tools, options) {
655
655
  const p = getProvider(provider);
656
656
  const startTime = Date.now();
657
+ // Teacher logger — captures (prompt, response) pairs for later distillation.
658
+ // Disabled for local providers (already free) and when KBOT_TEACHER_LOG=0.
659
+ const { getTeacherLogger } = await import('./teacher-logger.js');
660
+ const teacher = getTeacherLogger();
661
+ const teacherId = (teacher.isEnabled() && !isLocalProvider(provider))
662
+ ? teacher.begin({
663
+ sessionId: options?.sessionId,
664
+ provider,
665
+ model,
666
+ system: systemContext,
667
+ messages: messages.map(m => ({ role: m.role, content: m.content })),
668
+ })
669
+ : '';
657
670
  try {
658
671
  let result;
659
672
  // Embedded inference — runs in-process via node-llama-cpp, no HTTP
@@ -692,6 +705,14 @@ async function callProvider(provider, apiKey, model, systemContext, messages, to
692
705
  }
693
706
  }
694
707
  recordSuccess(provider, Date.now() - startTime);
708
+ if (teacherId) {
709
+ teacher.end(teacherId, {
710
+ content: result.content,
711
+ thinking: result.thinking,
712
+ tool_calls: result.tool_calls,
713
+ stop_reason: result.stop_reason,
714
+ }, result.usage);
715
+ }
695
716
  return result;
696
717
  }
697
718
  catch (err) {
@@ -854,7 +875,7 @@ export async function runAgent(message, options = {}) {
854
875
  // Step 2: Build context (cached — only rebuilt when inputs change)
855
876
  const matrixPrompt = options.agent ? getMatrixSystemPrompt(options.agent) : null;
856
877
  const contextSnippet = options.context ? formatContextForPrompt(options.context) : '';
857
- const skillsSnippet = loadSkills(process.cwd());
878
+ const skillsSnippet = loadSkills(process.cwd(), message);
858
879
  const memorySnippet = getMemoryPrompt();
859
880
  const learningContext = buildFullLearningContext(message, process.cwd());
860
881
  const synthesisSnippet = getSynthesisContext(8); // Three-tier memory: reflection layer insights
package/dist/cli.js CHANGED
@@ -835,6 +835,50 @@ async function main() {
835
835
  ignorePatterns,
836
836
  });
837
837
  });
838
+ const skillsCmd = program.command('skills').description('Manage agent skills (agentskills.io format — compatible with Claude Skills, Hermes, Copilot)');
839
+ skillsCmd
840
+ .command('list')
841
+ .description('List all discovered skills')
842
+ .action(async () => {
843
+ const { discoverSkillFiles } = await import('./skills-loader.js');
844
+ const skills = discoverSkillFiles(process.cwd());
845
+ if (skills.length === 0) {
846
+ printInfo('No skills found. Run `kbot skills import --from hermes` to import 76 Hermes skills.');
847
+ return;
848
+ }
849
+ printInfo(`Found ${skills.length} skill${skills.length === 1 ? '' : 's'}:\n`);
850
+ for (const s of skills) {
851
+ const desc = s.description ? ` — ${s.description.slice(0, 70)}` : '';
852
+ printInfo(` ${s.name}${desc}`);
853
+ }
854
+ });
855
+ skillsCmd
856
+ .command('import')
857
+ .description('Import skills from an external agent (Hermes, Claude, or a custom directory)')
858
+ .option('--from <source>', 'Source: hermes, claude, or an absolute path', 'hermes')
859
+ .action(async (opts) => {
860
+ const { importExternalSkills } = await import('./skills-loader.js');
861
+ const { homedir } = await import('node:os');
862
+ const { join } = await import('node:path');
863
+ const { existsSync } = await import('node:fs');
864
+ const sources = {
865
+ hermes: join(homedir(), '.hermes', 'skills'),
866
+ claude: join(homedir(), '.claude', 'skills'),
867
+ };
868
+ const from = opts.from || 'hermes';
869
+ const src = sources[from] || from;
870
+ if (!existsSync(src)) {
871
+ printError(`Source not found: ${src}`);
872
+ if (from === 'hermes')
873
+ printInfo('Install Hermes: `ollama launch hermes --yes --model hermes3:8b`');
874
+ return;
875
+ }
876
+ const result = await importExternalSkills(src);
877
+ printSuccess(`Imported ${result.imported} skill${result.imported === 1 ? '' : 's'} from ${src}`);
878
+ if (result.skipped > 0)
879
+ printInfo(` ${result.skipped} skipped (existing user-authored files preserved)`);
880
+ printInfo(` → ${result.destination}`);
881
+ });
838
882
  program
839
883
  .command('doctor')
840
884
  .description('Diagnose your kbot setup — check everything is working')
@@ -3875,6 +3919,125 @@ async function main() {
3875
3919
  pikaCmd.action(() => {
3876
3920
  pikaCmd.commands.find(c => c.name() === 'status')?.parse(['', '', 'status']);
3877
3921
  });
3922
+ // ── train-self / train-cycle / train-merge / train-grpo ──
3923
+ // Fine-tune a local model on your own agent sessions.
3924
+ program
3925
+ .command('train-self')
3926
+ .description('Fine-tune a local model on your own kbot sessions (MLX LoRA)')
3927
+ .option('--mode <mode>', 'default | reasoning | agent-trace | code-only', 'default')
3928
+ .option('--base-model <model>', 'Override base model (HF path or mlx-community/*)')
3929
+ .option('--output-name <name>', 'Ollama model name to register')
3930
+ .option('--backend <backend>', 'mlx | unsloth | llama-cpp | together', 'mlx')
3931
+ .option('--iters <n>', 'Training iterations', (v) => parseInt(v, 10))
3932
+ .option('--batch-size <n>', 'Batch size', (v) => parseInt(v, 10))
3933
+ .option('--num-layers <n>', 'LoRA layers', (v) => parseInt(v, 10))
3934
+ .option('--learning-rate <lr>', 'Learning rate', parseFloat)
3935
+ .option('--max-examples <n>', 'Cap curated examples', (v) => parseInt(v, 10))
3936
+ .option('--dry-run', 'Curate only, do not train')
3937
+ .option('--skip-curate', 'Skip curation (use existing dataset)')
3938
+ .option('--skip-train', 'Skip training (prepare + deploy only)')
3939
+ .option('--skip-deploy', 'Skip Ollama deploy')
3940
+ .option('--no-grad-checkpoint', 'Disable gradient checkpointing')
3941
+ .action(async (opts) => {
3942
+ const { trainSelf, formatTrainSelfReport } = await import('./train-self.js');
3943
+ const r = await trainSelf({
3944
+ mode: opts.mode,
3945
+ baseModel: opts.baseModel,
3946
+ outputName: opts.outputName,
3947
+ backend: opts.backend,
3948
+ iters: opts.iters,
3949
+ batchSize: opts.batchSize,
3950
+ numLayers: opts.numLayers,
3951
+ learningRate: opts.learningRate,
3952
+ maxExamples: opts.maxExamples,
3953
+ dryRun: Boolean(opts.dryRun),
3954
+ skipCurate: Boolean(opts.skipCurate),
3955
+ skipTrain: Boolean(opts.skipTrain),
3956
+ skipDeploy: Boolean(opts.skipDeploy),
3957
+ gradCheckpoint: opts.gradCheckpoint !== false,
3958
+ });
3959
+ console.log(formatTrainSelfReport(r));
3960
+ });
3961
+ program
3962
+ .command('train-cycle')
3963
+ .description('On-policy distillation: student generates → Claude grades/corrects → retrain')
3964
+ .option('--student <model>', 'Local student model (Ollama)', 'kernel-coder:latest')
3965
+ .option('--teacher <model>', 'Teacher model', 'claude-opus-4-6')
3966
+ .option('--samples <n>', 'Prompts to sample per cycle', (v) => parseInt(v, 10), 50)
3967
+ .option('--threshold <score>', 'Pass threshold 0..1', parseFloat, 0.6)
3968
+ .option('--retrain', 'Trigger train-self after collecting corrections')
3969
+ .option('--dry-run', 'Skip teacher grading, just test student generation')
3970
+ .action(async (opts) => {
3971
+ const { runCycle, formatCycleReport } = await import('./train-cycle.js');
3972
+ const r = await runCycle({
3973
+ studentModel: opts.student,
3974
+ teacherModel: opts.teacher,
3975
+ samples: opts.samples,
3976
+ passThreshold: opts.threshold,
3977
+ retrain: Boolean(opts.retrain),
3978
+ dryRun: Boolean(opts.dryRun),
3979
+ });
3980
+ console.log(formatCycleReport(r));
3981
+ });
3982
+ program
3983
+ .command('train-merge')
3984
+ .description('Merge models via MergeKit (TIES/SLERP/DARE)')
3985
+ .option('--method <method>', 'ties | slerp | dare_ties | linear', 'ties')
3986
+ .option('--base <model>', 'Base model (HF path)', 'Qwen/Qwen2.5-Coder-7B-Instruct')
3987
+ .option('--output <name>', 'Output name')
3988
+ .option('--default', 'Use kbot triad defaults (qwen-coder + deepseek-r1 + self)')
3989
+ .option('--deploy', 'Register with Ollama after merge')
3990
+ .action(async (opts) => {
3991
+ const { mergeKbotDefault, mergeModels, formatMergeReport } = await import('./train-merge.js');
3992
+ if (opts.default) {
3993
+ const r = await mergeKbotDefault();
3994
+ console.log(formatMergeReport(r));
3995
+ return;
3996
+ }
3997
+ const r = await mergeModels({
3998
+ method: opts.method,
3999
+ baseModel: opts.base,
4000
+ models: [
4001
+ { model: opts.base, weight: 1, density: 0.5 },
4002
+ ],
4003
+ outputName: opts.output,
4004
+ deploy: Boolean(opts.deploy),
4005
+ });
4006
+ console.log(formatMergeReport(r));
4007
+ });
4008
+ program
4009
+ .command('train-grpo')
4010
+ .description('GRPO on verifiable tasks (build-pass, test-pass, regex-match, json-valid)')
4011
+ .option('--student <model>', 'Student model', 'kernel-coder:latest')
4012
+ .option('--group-size <n>', 'Rollouts per prompt', (v) => parseInt(v, 10), 8)
4013
+ .option('--iters <n>', 'Outer iterations', (v) => parseInt(v, 10), 100)
4014
+ .option('--dry-run', 'Collect rollouts only, do not update weights')
4015
+ .option('--runner-cmd <cmd>', 'External GRPO runner command')
4016
+ .action(async (opts) => {
4017
+ const { runGrpoRollouts, DEFAULT_VERIFIER_SUITE, formatGrpoReport } = await import('./train-grpo.js');
4018
+ const r = await runGrpoRollouts({
4019
+ studentModel: opts.student,
4020
+ prompts: DEFAULT_VERIFIER_SUITE,
4021
+ groupSize: opts.groupSize,
4022
+ iters: opts.iters,
4023
+ dryRun: Boolean(opts.dryRun),
4024
+ runnerCmd: opts.runnerCmd,
4025
+ });
4026
+ console.log(formatGrpoReport(r));
4027
+ });
4028
+ program
4029
+ .command('train-agent-trace')
4030
+ .description('Reformat tool-use traces as agent training examples')
4031
+ .option('--min-tools <n>', 'Minimum tool calls per trajectory', (v) => parseInt(v, 10), 1)
4032
+ .option('--verified-only', 'Only use trajectories tagged verified')
4033
+ .action(async (opts) => {
4034
+ const { formatAgentTraces, formatAgentTraceReport } = await import('./train-agent-trace.js');
4035
+ const r = formatAgentTraces({
4036
+ minTools: opts.minTools,
4037
+ verifiedOnly: Boolean(opts.verifiedOnly),
4038
+ });
4039
+ console.log(formatAgentTraceReport(r));
4040
+ });
3878
4041
  program.parse(process.argv);
3879
4042
  const opts = program.opts();
3880
4043
  const promptArgs = program.args;
@@ -2,16 +2,48 @@ export interface SkillFile {
2
2
  name: string;
3
3
  path: string;
4
4
  content: string;
5
+ description: string;
6
+ tags: string[];
5
7
  tokens: number;
8
+ /** Skill only activates when these toolsets are available (Hermes: requires_toolsets) */
9
+ requiresToolsets: string[];
10
+ /** Skill only activates when these toolsets are UNAVAILABLE (fallback path) */
11
+ fallbackForToolsets: string[];
12
+ /** OS platforms this skill supports; empty = all */
13
+ platforms: string[];
14
+ /** Related skill names */
15
+ relatedSkills: string[];
16
+ /** True for skills that ship with kbot or declare `metadata.kbot.*` — boosted in ranking */
17
+ native: boolean;
18
+ }
19
+ export interface SkillLoadContext {
20
+ /** Toolsets currently available — skills can require/fall-back based on these */
21
+ availableToolsets?: string[];
22
+ /** Current OS platform, e.g. 'darwin' | 'linux' | 'win32' */
23
+ platform?: string;
6
24
  }
7
25
  /**
8
- * Discover and load skill files from project and global directories.
9
- * Returns formatted string ready to inject into system prompt.
26
+ * Discover and load skill files. Returns a prompt-ready string.
27
+ * When `message` is provided, skills are scored for relevance and only the
28
+ * most relevant are included (keeps token budget tight with a large library).
10
29
  */
11
- export declare function loadSkills(projectRoot: string): string;
30
+ export declare function loadSkills(projectRoot: string, message?: string, ctx?: SkillLoadContext): string;
12
31
  /**
13
- * Discover .md files from both project-local and global skill directories.
14
- * Project skills take precedence (loaded first, consume token budget first).
32
+ * Walk both skill roots and return every skill document found.
33
+ * Handles flat files (name.md) AND subdirectory layouts (cat/name/SKILL.md).
34
+ * Project skills take precedence over global skills with the same name.
15
35
  */
16
36
  export declare function discoverSkillFiles(projectRoot: string): SkillFile[];
37
+ export interface ImportResult {
38
+ imported: number;
39
+ skipped: number;
40
+ source: string;
41
+ destination: string;
42
+ }
43
+ /**
44
+ * Copy (as symlinks) every SKILL.md under a foreign skills directory
45
+ * into ~/.kbot/skills/imported/<category>/<name>/SKILL.md.
46
+ * Non-destructive: existing symlinks are replaced, real files are skipped.
47
+ */
48
+ export declare function importExternalSkills(sourceRoot: string): Promise<ImportResult>;
17
49
  //# sourceMappingURL=skills-loader.d.ts.map