@elisym/sdk 0.12.3 → 0.12.5
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/dist/agent-store.cjs +2 -0
- package/dist/agent-store.cjs.map +1 -1
- package/dist/agent-store.js +2 -0
- package/dist/agent-store.js.map +1 -1
- package/dist/index.cjs +33 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -1
- package/dist/index.d.ts +36 -1
- package/dist/index.js +32 -1
- package/dist/index.js.map +1 -1
- package/dist/node.cjs.map +1 -1
- package/dist/node.js.map +1 -1
- package/dist/skills.cjs +392 -88
- package/dist/skills.cjs.map +1 -1
- package/dist/skills.d.cts +183 -3
- package/dist/skills.d.ts +183 -3
- package/dist/skills.js +385 -89
- package/dist/skills.js.map +1 -1
- package/package.json +1 -1
package/dist/skills.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { StringDecoder } from 'node:string_decoder';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { dirname, resolve, relative, sep, join } from 'node:path';
|
|
3
5
|
import { readdirSync, statSync, readFileSync } from 'node:fs';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
6
|
import YAML from 'yaml';
|
|
6
7
|
import Decimal from 'decimal.js-light';
|
|
7
8
|
|
|
@@ -22,9 +23,9 @@ function sleepWithSignal(ms, signal) {
|
|
|
22
23
|
return Promise.reject(createAbortError());
|
|
23
24
|
}
|
|
24
25
|
if (!signal) {
|
|
25
|
-
return new Promise((
|
|
26
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
26
27
|
}
|
|
27
|
-
return new Promise((
|
|
28
|
+
return new Promise((resolve2, reject) => {
|
|
28
29
|
const cleanup = () => {
|
|
29
30
|
clearTimeout(timer);
|
|
30
31
|
signal.removeEventListener("abort", onAbort);
|
|
@@ -35,7 +36,7 @@ function sleepWithSignal(ms, signal) {
|
|
|
35
36
|
};
|
|
36
37
|
const timer = setTimeout(() => {
|
|
37
38
|
cleanup();
|
|
38
|
-
|
|
39
|
+
resolve2();
|
|
39
40
|
}, ms);
|
|
40
41
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
41
42
|
});
|
|
@@ -302,14 +303,61 @@ function createLlmClient(config) {
|
|
|
302
303
|
}
|
|
303
304
|
return createAnthropicClient(config);
|
|
304
305
|
}
|
|
305
|
-
var
|
|
306
|
-
var
|
|
306
|
+
var MAX_SCRIPT_OUTPUT = 1e6;
|
|
307
|
+
var DEFAULT_SCRIPT_TIMEOUT_MS = 6e4;
|
|
308
|
+
function runScript(cmd, args, opts) {
|
|
309
|
+
return new Promise((resolveResult) => {
|
|
310
|
+
const maxOutput = opts.maxOutput ?? MAX_SCRIPT_OUTPUT;
|
|
311
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_SCRIPT_TIMEOUT_MS;
|
|
312
|
+
const child = spawn(cmd, args, {
|
|
313
|
+
cwd: opts.cwd,
|
|
314
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
315
|
+
timeout: timeoutMs,
|
|
316
|
+
killSignal: "SIGKILL",
|
|
317
|
+
signal: opts.signal
|
|
318
|
+
});
|
|
319
|
+
let stdout = "";
|
|
320
|
+
let stderr = "";
|
|
321
|
+
const stdoutDecoder = new StringDecoder("utf8");
|
|
322
|
+
const stderrDecoder = new StringDecoder("utf8");
|
|
323
|
+
child.stdout?.on("data", (data) => {
|
|
324
|
+
if (stdout.length < maxOutput) {
|
|
325
|
+
stdout += stdoutDecoder.write(data);
|
|
326
|
+
if (stdout.length > maxOutput) {
|
|
327
|
+
stdout = stdout.slice(0, maxOutput);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
child.stderr?.on("data", (data) => {
|
|
332
|
+
if (stderr.length < maxOutput) {
|
|
333
|
+
stderr += stderrDecoder.write(data);
|
|
334
|
+
if (stderr.length > maxOutput) {
|
|
335
|
+
stderr = stderr.slice(0, maxOutput);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
child.on("close", (code) => {
|
|
340
|
+
stdout += stdoutDecoder.end();
|
|
341
|
+
stderr += stderrDecoder.end();
|
|
342
|
+
resolveResult({ stdout, stderr, code });
|
|
343
|
+
});
|
|
344
|
+
child.on("error", (err) => {
|
|
345
|
+
resolveResult({ stdout, stderr, code: null, spawnError: err });
|
|
346
|
+
});
|
|
347
|
+
if (child.stdin) {
|
|
348
|
+
child.stdin.on("error", () => {
|
|
349
|
+
});
|
|
350
|
+
child.stdin.end(opts.stdin ?? "");
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
307
354
|
var ScriptSkill = class {
|
|
308
355
|
name;
|
|
309
356
|
description;
|
|
310
357
|
capabilities;
|
|
311
358
|
priceSubunits;
|
|
312
359
|
asset;
|
|
360
|
+
mode = "llm";
|
|
313
361
|
image;
|
|
314
362
|
imageFile;
|
|
315
363
|
skillDir;
|
|
@@ -381,76 +429,163 @@ var ScriptSkill = class {
|
|
|
381
429
|
}
|
|
382
430
|
throw new Error(`Max tool rounds (${this.maxToolRounds}) exceeded`);
|
|
383
431
|
}
|
|
384
|
-
runTool(toolDef, call, signal) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
432
|
+
async runTool(toolDef, call, signal) {
|
|
433
|
+
const args = [...toolDef.command];
|
|
434
|
+
const cmd = args.shift();
|
|
435
|
+
if (!cmd) {
|
|
436
|
+
return `Error: tool "${toolDef.name}" has an empty command`;
|
|
437
|
+
}
|
|
438
|
+
const params = toolDef.parameters ?? [];
|
|
439
|
+
for (let index = 0; index < params.length; index++) {
|
|
440
|
+
const param = params[index];
|
|
441
|
+
if (!param) {
|
|
442
|
+
continue;
|
|
391
443
|
}
|
|
392
|
-
const
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
if (!param) {
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
|
-
const value = call.arguments[param.name];
|
|
399
|
-
if (value === void 0) {
|
|
400
|
-
continue;
|
|
401
|
-
}
|
|
402
|
-
if (param.required && index === 0) {
|
|
403
|
-
args.push(String(value));
|
|
404
|
-
} else {
|
|
405
|
-
args.push(`--${param.name}`, String(value));
|
|
406
|
-
}
|
|
444
|
+
const value = call.arguments[param.name];
|
|
445
|
+
if (value === void 0) {
|
|
446
|
+
continue;
|
|
407
447
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
448
|
+
if (param.required && index === 0) {
|
|
449
|
+
args.push(String(value));
|
|
450
|
+
} else {
|
|
451
|
+
args.push(`--${param.name}`, String(value));
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
const result = await runScript(cmd, args, { cwd: this.skillDir, signal });
|
|
455
|
+
if (result.spawnError) {
|
|
456
|
+
return `Error: ${result.spawnError.message}`;
|
|
457
|
+
}
|
|
458
|
+
if (result.code === 0) {
|
|
459
|
+
return result.stdout.trim();
|
|
460
|
+
}
|
|
461
|
+
this.logger.debug?.(
|
|
462
|
+
{ tool: toolDef.name, code: result.code, stderrLen: result.stderr.length },
|
|
463
|
+
"skill tool exited non-zero"
|
|
464
|
+
);
|
|
465
|
+
return `Error (exit ${result.code}): ${result.stderr.trim() || result.stdout.trim()}`;
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
var MAX_STATIC_FILE_SIZE = 256 * 1024;
|
|
469
|
+
var StaticFileSkill = class {
|
|
470
|
+
name;
|
|
471
|
+
description;
|
|
472
|
+
capabilities;
|
|
473
|
+
priceSubunits;
|
|
474
|
+
asset;
|
|
475
|
+
mode = "static-file";
|
|
476
|
+
image;
|
|
477
|
+
imageFile;
|
|
478
|
+
outputFilePath;
|
|
479
|
+
constructor(params) {
|
|
480
|
+
this.name = params.name;
|
|
481
|
+
this.description = params.description;
|
|
482
|
+
this.capabilities = params.capabilities;
|
|
483
|
+
this.priceSubunits = params.priceSubunits;
|
|
484
|
+
this.asset = params.asset;
|
|
485
|
+
this.image = params.image;
|
|
486
|
+
this.imageFile = params.imageFile;
|
|
487
|
+
this.outputFilePath = params.outputFilePath;
|
|
488
|
+
}
|
|
489
|
+
async execute(_input, _ctx) {
|
|
490
|
+
const buffer = await readFile(this.outputFilePath);
|
|
491
|
+
if (buffer.length > MAX_STATIC_FILE_SIZE) {
|
|
492
|
+
throw new Error(
|
|
493
|
+
`static-file output exceeds ${MAX_STATIC_FILE_SIZE} bytes (got ${buffer.length})`
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
return { data: buffer.toString("utf-8") };
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
var StaticScriptSkill = class {
|
|
500
|
+
name;
|
|
501
|
+
description;
|
|
502
|
+
capabilities;
|
|
503
|
+
priceSubunits;
|
|
504
|
+
asset;
|
|
505
|
+
mode = "static-script";
|
|
506
|
+
image;
|
|
507
|
+
imageFile;
|
|
508
|
+
scriptPath;
|
|
509
|
+
scriptArgs;
|
|
510
|
+
scriptTimeoutMs;
|
|
511
|
+
constructor(params) {
|
|
512
|
+
this.name = params.name;
|
|
513
|
+
this.description = params.description;
|
|
514
|
+
this.capabilities = params.capabilities;
|
|
515
|
+
this.priceSubunits = params.priceSubunits;
|
|
516
|
+
this.asset = params.asset;
|
|
517
|
+
this.image = params.image;
|
|
518
|
+
this.imageFile = params.imageFile;
|
|
519
|
+
this.scriptPath = params.scriptPath;
|
|
520
|
+
this.scriptArgs = params.scriptArgs;
|
|
521
|
+
this.scriptTimeoutMs = params.scriptTimeoutMs;
|
|
522
|
+
}
|
|
523
|
+
async execute(_input, ctx) {
|
|
524
|
+
const result = await runScript(this.scriptPath, this.scriptArgs, {
|
|
525
|
+
cwd: dirname(this.scriptPath),
|
|
526
|
+
signal: ctx.signal,
|
|
527
|
+
timeoutMs: this.scriptTimeoutMs
|
|
528
|
+
});
|
|
529
|
+
if (result.spawnError) {
|
|
530
|
+
throw new Error(`script spawn failed: ${result.spawnError.message}`);
|
|
531
|
+
}
|
|
532
|
+
if (result.code !== 0) {
|
|
533
|
+
const detail = result.stderr.trim() || result.stdout.trim() || "(no output)";
|
|
534
|
+
throw new Error(`script failed (exit ${result.code}): ${detail}`);
|
|
535
|
+
}
|
|
536
|
+
return { data: result.stdout.trim() };
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
var DynamicScriptSkill = class {
|
|
540
|
+
name;
|
|
541
|
+
description;
|
|
542
|
+
capabilities;
|
|
543
|
+
priceSubunits;
|
|
544
|
+
asset;
|
|
545
|
+
mode = "dynamic-script";
|
|
546
|
+
image;
|
|
547
|
+
imageFile;
|
|
548
|
+
scriptPath;
|
|
549
|
+
scriptArgs;
|
|
550
|
+
scriptTimeoutMs;
|
|
551
|
+
constructor(params) {
|
|
552
|
+
this.name = params.name;
|
|
553
|
+
this.description = params.description;
|
|
554
|
+
this.capabilities = params.capabilities;
|
|
555
|
+
this.priceSubunits = params.priceSubunits;
|
|
556
|
+
this.asset = params.asset;
|
|
557
|
+
this.image = params.image;
|
|
558
|
+
this.imageFile = params.imageFile;
|
|
559
|
+
this.scriptPath = params.scriptPath;
|
|
560
|
+
this.scriptArgs = params.scriptArgs;
|
|
561
|
+
this.scriptTimeoutMs = params.scriptTimeoutMs;
|
|
562
|
+
}
|
|
563
|
+
async execute(input, ctx) {
|
|
564
|
+
const result = await runScript(this.scriptPath, this.scriptArgs, {
|
|
565
|
+
cwd: dirname(this.scriptPath),
|
|
566
|
+
stdin: input.data,
|
|
567
|
+
signal: ctx.signal,
|
|
568
|
+
timeoutMs: this.scriptTimeoutMs
|
|
451
569
|
});
|
|
570
|
+
if (result.spawnError) {
|
|
571
|
+
throw new Error(`script spawn failed: ${result.spawnError.message}`);
|
|
572
|
+
}
|
|
573
|
+
if (result.code !== 0) {
|
|
574
|
+
const detail = result.stderr.trim() || result.stdout.trim() || "(no output)";
|
|
575
|
+
throw new Error(`script failed (exit ${result.code}): ${detail}`);
|
|
576
|
+
}
|
|
577
|
+
return { data: result.stdout.trim() };
|
|
452
578
|
}
|
|
453
579
|
};
|
|
580
|
+
function resolveInsidePath(rootDir, value) {
|
|
581
|
+
const root = resolve(rootDir);
|
|
582
|
+
const candidate = resolve(root, value);
|
|
583
|
+
const rel = relative(root, candidate);
|
|
584
|
+
if (rel === "" || rel.startsWith("..") || rel.includes(`..${sep}`)) {
|
|
585
|
+
return null;
|
|
586
|
+
}
|
|
587
|
+
return candidate;
|
|
588
|
+
}
|
|
454
589
|
var LAMPORTS_PER_SOL = 1e9;
|
|
455
590
|
var NATIVE_SOL = {
|
|
456
591
|
chain: "solana",
|
|
@@ -520,6 +655,12 @@ Decimal.clone({ toExpNeg: -100, toExpPos: 100, precision: 50 });
|
|
|
520
655
|
|
|
521
656
|
// src/skills/loader.ts
|
|
522
657
|
var DEFAULT_MAX_TOOL_ROUNDS = 10;
|
|
658
|
+
var VALID_MODES = [
|
|
659
|
+
"llm",
|
|
660
|
+
"static-file",
|
|
661
|
+
"static-script",
|
|
662
|
+
"dynamic-script"
|
|
663
|
+
];
|
|
523
664
|
function solToLamports(sol) {
|
|
524
665
|
const asNumber = typeof sol === "string" ? Number(sol) : sol;
|
|
525
666
|
if (!Number.isFinite(asNumber) || asNumber < 0) {
|
|
@@ -636,6 +777,43 @@ function validateTool(raw, skillName, index) {
|
|
|
636
777
|
parameters
|
|
637
778
|
};
|
|
638
779
|
}
|
|
780
|
+
function validateMode(skillName, raw) {
|
|
781
|
+
if (raw === void 0 || raw === null) {
|
|
782
|
+
return "llm";
|
|
783
|
+
}
|
|
784
|
+
if (typeof raw !== "string") {
|
|
785
|
+
throw new Error(`SKILL.md "${skillName}": "mode" must be a string`);
|
|
786
|
+
}
|
|
787
|
+
if (!VALID_MODES.includes(raw)) {
|
|
788
|
+
throw new Error(
|
|
789
|
+
`SKILL.md "${skillName}": invalid mode "${raw}". Allowed: ${VALID_MODES.join(", ")}`
|
|
790
|
+
);
|
|
791
|
+
}
|
|
792
|
+
return raw;
|
|
793
|
+
}
|
|
794
|
+
function validateScriptArgs(skillName, raw) {
|
|
795
|
+
if (raw === void 0 || raw === null) {
|
|
796
|
+
return [];
|
|
797
|
+
}
|
|
798
|
+
if (!Array.isArray(raw)) {
|
|
799
|
+
throw new Error(`SKILL.md "${skillName}": "script_args" must be an array of strings`);
|
|
800
|
+
}
|
|
801
|
+
for (const part of raw) {
|
|
802
|
+
if (typeof part !== "string") {
|
|
803
|
+
throw new Error(`SKILL.md "${skillName}": "script_args" entries must be strings`);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
return raw;
|
|
807
|
+
}
|
|
808
|
+
function validateScriptTimeoutMs(skillName, raw) {
|
|
809
|
+
if (raw === void 0 || raw === null) {
|
|
810
|
+
return void 0;
|
|
811
|
+
}
|
|
812
|
+
if (typeof raw !== "number" || !Number.isInteger(raw) || raw <= 0) {
|
|
813
|
+
throw new Error(`SKILL.md "${skillName}": "script_timeout_ms" must be a positive integer`);
|
|
814
|
+
}
|
|
815
|
+
return raw;
|
|
816
|
+
}
|
|
639
817
|
function validateSkillFrontmatter(frontmatter, systemPrompt, options = {}) {
|
|
640
818
|
if (typeof frontmatter.name !== "string" || frontmatter.name.length === 0) {
|
|
641
819
|
throw new Error('SKILL.md: missing or invalid "name" field');
|
|
@@ -687,8 +865,14 @@ function validateSkillFrontmatter(frontmatter, systemPrompt, options = {}) {
|
|
|
687
865
|
);
|
|
688
866
|
}
|
|
689
867
|
}
|
|
868
|
+
const mode = validateMode(frontmatter.name, frontmatter.mode);
|
|
690
869
|
const tools = [];
|
|
691
870
|
if (frontmatter.tools !== void 0) {
|
|
871
|
+
if (mode !== "llm") {
|
|
872
|
+
throw new Error(
|
|
873
|
+
`SKILL.md "${frontmatter.name}": "tools" is only valid in mode 'llm' (got '${mode}')`
|
|
874
|
+
);
|
|
875
|
+
}
|
|
692
876
|
if (!Array.isArray(frontmatter.tools)) {
|
|
693
877
|
throw new Error(`SKILL.md "${frontmatter.name}": "tools" must be an array`);
|
|
694
878
|
}
|
|
@@ -698,6 +882,11 @@ function validateSkillFrontmatter(frontmatter, systemPrompt, options = {}) {
|
|
|
698
882
|
}
|
|
699
883
|
let maxToolRounds = DEFAULT_MAX_TOOL_ROUNDS;
|
|
700
884
|
if (frontmatter.max_tool_rounds !== void 0) {
|
|
885
|
+
if (mode !== "llm") {
|
|
886
|
+
throw new Error(
|
|
887
|
+
`SKILL.md "${frontmatter.name}": "max_tool_rounds" is only valid in mode 'llm' (got '${mode}')`
|
|
888
|
+
);
|
|
889
|
+
}
|
|
701
890
|
if (typeof frontmatter.max_tool_rounds !== "number" || !Number.isInteger(frontmatter.max_tool_rounds) || frontmatter.max_tool_rounds <= 0) {
|
|
702
891
|
throw new Error(
|
|
703
892
|
`SKILL.md "${frontmatter.name}": "max_tool_rounds" must be a positive integer`
|
|
@@ -705,6 +894,56 @@ function validateSkillFrontmatter(frontmatter, systemPrompt, options = {}) {
|
|
|
705
894
|
}
|
|
706
895
|
maxToolRounds = frontmatter.max_tool_rounds;
|
|
707
896
|
}
|
|
897
|
+
let outputFile;
|
|
898
|
+
let script;
|
|
899
|
+
let scriptArgs = [];
|
|
900
|
+
let scriptTimeoutMs;
|
|
901
|
+
if (mode === "static-file") {
|
|
902
|
+
if (typeof frontmatter.output_file !== "string" || frontmatter.output_file.length === 0) {
|
|
903
|
+
throw new Error(
|
|
904
|
+
`SKILL.md "${frontmatter.name}": mode 'static-file' requires "output_file" (string)`
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
if (frontmatter.script !== void 0) {
|
|
908
|
+
throw new Error(
|
|
909
|
+
`SKILL.md "${frontmatter.name}": "script" is not valid in mode 'static-file'`
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
outputFile = frontmatter.output_file;
|
|
913
|
+
} else if (mode === "static-script" || mode === "dynamic-script") {
|
|
914
|
+
if (typeof frontmatter.script !== "string" || frontmatter.script.length === 0) {
|
|
915
|
+
throw new Error(`SKILL.md "${frontmatter.name}": mode '${mode}' requires "script" (string)`);
|
|
916
|
+
}
|
|
917
|
+
if (frontmatter.output_file !== void 0) {
|
|
918
|
+
throw new Error(
|
|
919
|
+
`SKILL.md "${frontmatter.name}": "output_file" is only valid in mode 'static-file'`
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
script = frontmatter.script;
|
|
923
|
+
scriptArgs = validateScriptArgs(frontmatter.name, frontmatter.script_args);
|
|
924
|
+
scriptTimeoutMs = validateScriptTimeoutMs(frontmatter.name, frontmatter.script_timeout_ms);
|
|
925
|
+
} else {
|
|
926
|
+
if (frontmatter.output_file !== void 0) {
|
|
927
|
+
throw new Error(
|
|
928
|
+
`SKILL.md "${frontmatter.name}": "output_file" is only valid in mode 'static-file'`
|
|
929
|
+
);
|
|
930
|
+
}
|
|
931
|
+
if (frontmatter.script !== void 0) {
|
|
932
|
+
throw new Error(
|
|
933
|
+
`SKILL.md "${frontmatter.name}": "script" is only valid in script modes (static-script, dynamic-script)`
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
if (frontmatter.script_args !== void 0) {
|
|
937
|
+
throw new Error(
|
|
938
|
+
`SKILL.md "${frontmatter.name}": "script_args" is only valid in script modes`
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
if (frontmatter.script_timeout_ms !== void 0) {
|
|
942
|
+
throw new Error(
|
|
943
|
+
`SKILL.md "${frontmatter.name}": "script_timeout_ms" is only valid in script modes`
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
708
947
|
const image = typeof frontmatter.image === "string" ? frontmatter.image : void 0;
|
|
709
948
|
const imageFile = typeof frontmatter.image_file === "string" ? frontmatter.image_file : void 0;
|
|
710
949
|
return {
|
|
@@ -713,13 +952,85 @@ function validateSkillFrontmatter(frontmatter, systemPrompt, options = {}) {
|
|
|
713
952
|
capabilities,
|
|
714
953
|
priceSubunits,
|
|
715
954
|
asset,
|
|
955
|
+
mode,
|
|
716
956
|
systemPrompt,
|
|
717
957
|
tools,
|
|
718
958
|
maxToolRounds,
|
|
719
959
|
image,
|
|
720
|
-
imageFile
|
|
960
|
+
imageFile,
|
|
961
|
+
outputFile,
|
|
962
|
+
script,
|
|
963
|
+
scriptArgs,
|
|
964
|
+
scriptTimeoutMs
|
|
721
965
|
};
|
|
722
966
|
}
|
|
967
|
+
function buildSkillFromParsed(parsed, skillDir, logger) {
|
|
968
|
+
switch (parsed.mode) {
|
|
969
|
+
case "llm":
|
|
970
|
+
return new ScriptSkill({
|
|
971
|
+
name: parsed.name,
|
|
972
|
+
description: parsed.description,
|
|
973
|
+
capabilities: parsed.capabilities,
|
|
974
|
+
priceSubunits: parsed.priceSubunits,
|
|
975
|
+
asset: parsed.asset,
|
|
976
|
+
skillDir,
|
|
977
|
+
systemPrompt: parsed.systemPrompt,
|
|
978
|
+
tools: parsed.tools,
|
|
979
|
+
maxToolRounds: parsed.maxToolRounds,
|
|
980
|
+
image: parsed.image,
|
|
981
|
+
imageFile: parsed.imageFile,
|
|
982
|
+
logger
|
|
983
|
+
});
|
|
984
|
+
case "static-file": {
|
|
985
|
+
if (parsed.outputFile === void 0) {
|
|
986
|
+
throw new Error(
|
|
987
|
+
`SKILL.md "${parsed.name}": internal error - outputFile missing for mode 'static-file'`
|
|
988
|
+
);
|
|
989
|
+
}
|
|
990
|
+
const outputFilePath = resolveInsidePath(skillDir, parsed.outputFile);
|
|
991
|
+
if (!outputFilePath) {
|
|
992
|
+
throw new Error(
|
|
993
|
+
`SKILL.md "${parsed.name}": "output_file" must stay inside the skill directory`
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
return new StaticFileSkill({
|
|
997
|
+
name: parsed.name,
|
|
998
|
+
description: parsed.description,
|
|
999
|
+
capabilities: parsed.capabilities,
|
|
1000
|
+
priceSubunits: parsed.priceSubunits,
|
|
1001
|
+
asset: parsed.asset,
|
|
1002
|
+
outputFilePath,
|
|
1003
|
+
image: parsed.image,
|
|
1004
|
+
imageFile: parsed.imageFile
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
case "static-script":
|
|
1008
|
+
case "dynamic-script": {
|
|
1009
|
+
if (parsed.script === void 0) {
|
|
1010
|
+
throw new Error(
|
|
1011
|
+
`SKILL.md "${parsed.name}": internal error - script missing for mode '${parsed.mode}'`
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
const scriptPath = resolveInsidePath(skillDir, parsed.script);
|
|
1015
|
+
if (!scriptPath) {
|
|
1016
|
+
throw new Error(`SKILL.md "${parsed.name}": "script" must stay inside the skill directory`);
|
|
1017
|
+
}
|
|
1018
|
+
const Ctor = parsed.mode === "static-script" ? StaticScriptSkill : DynamicScriptSkill;
|
|
1019
|
+
return new Ctor({
|
|
1020
|
+
name: parsed.name,
|
|
1021
|
+
description: parsed.description,
|
|
1022
|
+
capabilities: parsed.capabilities,
|
|
1023
|
+
priceSubunits: parsed.priceSubunits,
|
|
1024
|
+
asset: parsed.asset,
|
|
1025
|
+
scriptPath,
|
|
1026
|
+
scriptArgs: parsed.scriptArgs,
|
|
1027
|
+
scriptTimeoutMs: parsed.scriptTimeoutMs ?? DEFAULT_SCRIPT_TIMEOUT_MS,
|
|
1028
|
+
image: parsed.image,
|
|
1029
|
+
imageFile: parsed.imageFile
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
723
1034
|
function loadSkillsFromDir(skillsDir, options = {}) {
|
|
724
1035
|
const logger = options.logger ?? {};
|
|
725
1036
|
const skills = [];
|
|
@@ -744,22 +1055,7 @@ function loadSkillsFromDir(skillsDir, options = {}) {
|
|
|
744
1055
|
const content = readFileSync(skillMdPath, "utf-8");
|
|
745
1056
|
const { frontmatter, systemPrompt } = parseSkillMd(content);
|
|
746
1057
|
const parsed = validateSkillFrontmatter(frontmatter, systemPrompt, options);
|
|
747
|
-
skills.push(
|
|
748
|
-
new ScriptSkill({
|
|
749
|
-
name: parsed.name,
|
|
750
|
-
description: parsed.description,
|
|
751
|
-
capabilities: parsed.capabilities,
|
|
752
|
-
priceSubunits: parsed.priceSubunits,
|
|
753
|
-
asset: parsed.asset,
|
|
754
|
-
skillDir: entryPath,
|
|
755
|
-
systemPrompt: parsed.systemPrompt,
|
|
756
|
-
tools: parsed.tools,
|
|
757
|
-
maxToolRounds: parsed.maxToolRounds,
|
|
758
|
-
image: parsed.image,
|
|
759
|
-
imageFile: parsed.imageFile,
|
|
760
|
-
logger
|
|
761
|
-
})
|
|
762
|
-
);
|
|
1058
|
+
skills.push(buildSkillFromParsed(parsed, entryPath, logger));
|
|
763
1059
|
} catch (error) {
|
|
764
1060
|
const message = error instanceof Error ? error.message : String(error);
|
|
765
1061
|
logger.warn?.({ dir: entry, err: message }, "skipping malformed skill directory");
|
|
@@ -768,6 +1064,6 @@ function loadSkillsFromDir(skillsDir, options = {}) {
|
|
|
768
1064
|
return skills;
|
|
769
1065
|
}
|
|
770
1066
|
|
|
771
|
-
export { DEFAULT_MAX_TOOL_ROUNDS, ScriptSkill, createAnthropicClient, createLlmClient, createOpenAIClient, loadSkillsFromDir, parseSkillMd, validateSkillFrontmatter };
|
|
1067
|
+
export { DEFAULT_MAX_TOOL_ROUNDS, DEFAULT_SCRIPT_TIMEOUT_MS, DynamicScriptSkill, MAX_SCRIPT_OUTPUT, MAX_STATIC_FILE_SIZE, ScriptSkill, StaticFileSkill, StaticScriptSkill, createAnthropicClient, createLlmClient, createOpenAIClient, loadSkillsFromDir, parseSkillMd, resolveInsidePath, runScript, validateSkillFrontmatter };
|
|
772
1068
|
//# sourceMappingURL=skills.js.map
|
|
773
1069
|
//# sourceMappingURL=skills.js.map
|