@elisym/sdk 0.22.0 → 0.24.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/dist/agent-store.cjs +22 -0
- package/dist/agent-store.cjs.map +1 -1
- package/dist/agent-store.d.cts +9 -1
- package/dist/agent-store.d.ts +9 -1
- package/dist/agent-store.js +23 -2
- package/dist/agent-store.js.map +1 -1
- package/dist/{global-schema-CddHP2nk.d.cts → global-schema-BsVFDtkt.d.cts} +8 -8
- package/dist/{global-schema-CddHP2nk.d.ts → global-schema-BsVFDtkt.d.ts} +8 -8
- package/dist/index.cjs +177 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +223 -8
- package/dist/index.d.ts +223 -8
- package/dist/index.js +174 -28
- package/dist/index.js.map +1 -1
- package/dist/llm-health.cjs +11 -0
- package/dist/llm-health.cjs.map +1 -1
- package/dist/llm-health.d.cts +2 -2
- package/dist/llm-health.d.ts +2 -2
- package/dist/llm-health.js +11 -1
- package/dist/llm-health.js.map +1 -1
- package/dist/node.cjs +181 -1
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +47 -2
- package/dist/node.d.ts +47 -2
- package/dist/node.js +181 -2
- package/dist/node.js.map +1 -1
- package/dist/skills.cjs +183 -38
- package/dist/skills.cjs.map +1 -1
- package/dist/skills.d.cts +49 -1
- package/dist/skills.d.ts +49 -1
- package/dist/skills.js +185 -40
- package/dist/skills.js.map +1 -1
- package/dist/{types-COvV499T.d.cts → types-Cdscy9kY.d.cts} +13 -1
- package/dist/{types-COvV499T.d.ts → types-Cdscy9kY.d.ts} +13 -1
- package/package.json +4 -1
package/dist/skills.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as Asset } from './assets-C-nzSYD4.cjs';
|
|
2
|
-
import { S as SkillRateLimit } from './types-
|
|
2
|
+
import { S as SkillRateLimit } from './types-Cdscy9kY.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Shared SKILL.md runtime types. A skill is a markdown document whose
|
|
@@ -12,10 +12,29 @@ interface SkillInput {
|
|
|
12
12
|
inputType: string;
|
|
13
13
|
tags: string[];
|
|
14
14
|
jobId: string;
|
|
15
|
+
/**
|
|
16
|
+
* Local path to a file input fetched out-of-band (P2P via iroh), when the job
|
|
17
|
+
* carried a file attachment. The runtime fetches it after payment and removes
|
|
18
|
+
* it after execution; the skill reads from disk rather than from `data`.
|
|
19
|
+
*/
|
|
20
|
+
filePath?: string;
|
|
15
21
|
}
|
|
16
22
|
interface SkillOutput {
|
|
17
23
|
data: string;
|
|
18
24
|
outputMime?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Local path to a file result. When set, the runtime seeds the file via iroh
|
|
27
|
+
* and the customer fetches it out-of-band; `data` carries any text note (or '').
|
|
28
|
+
* `outputMime` is reused as the attachment's mime.
|
|
29
|
+
*/
|
|
30
|
+
filePath?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Releases the resources backing `filePath` (e.g. a temp dir). The runtime
|
|
33
|
+
* calls it once it has seeded the file - or failed to - since seeding happens
|
|
34
|
+
* after `execute()` returns and the producer cannot release the file itself.
|
|
35
|
+
* Mirrors the input-side cleanup callback in the runtime's `resolveInputFile`.
|
|
36
|
+
*/
|
|
37
|
+
cleanup?: () => Promise<void>;
|
|
19
38
|
}
|
|
20
39
|
/**
|
|
21
40
|
* Optional per-skill LLM override declared in SKILL.md frontmatter.
|
|
@@ -342,6 +361,12 @@ interface DynamicScriptSkillParams {
|
|
|
342
361
|
* itself reads the key from its environment.
|
|
343
362
|
*/
|
|
344
363
|
llmOverride?: SkillLlmOverride;
|
|
364
|
+
/**
|
|
365
|
+
* MIME type the script declares for a file result (SKILL.md `output_mime`).
|
|
366
|
+
* Used only when the script writes a file to `ELISYM_OUTPUT_FILE`; becomes the
|
|
367
|
+
* iroh attachment's mime. Defaults to `application/octet-stream`.
|
|
368
|
+
*/
|
|
369
|
+
outputMime?: string;
|
|
345
370
|
}
|
|
346
371
|
/**
|
|
347
372
|
* Pipes the user's job input to the script's stdin and returns its
|
|
@@ -363,6 +388,7 @@ declare class DynamicScriptSkill implements Skill {
|
|
|
363
388
|
private scriptArgs;
|
|
364
389
|
private scriptTimeoutMs?;
|
|
365
390
|
private scriptEnv?;
|
|
391
|
+
private outputMime?;
|
|
366
392
|
constructor(params: DynamicScriptSkillParams);
|
|
367
393
|
execute(input: SkillInput, ctx: SkillContext): Promise<SkillOutput>;
|
|
368
394
|
}
|
|
@@ -411,6 +437,20 @@ interface SkillFrontmatter {
|
|
|
411
437
|
script_args?: unknown;
|
|
412
438
|
/** Optional override of `DEFAULT_SCRIPT_TIMEOUT_MS`. */
|
|
413
439
|
script_timeout_ms?: unknown;
|
|
440
|
+
/**
|
|
441
|
+
* MIME type for a file result. Only valid in mode 'dynamic-script' (the only
|
|
442
|
+
* mode that can emit a file via `ELISYM_OUTPUT_FILE`). Becomes the iroh
|
|
443
|
+
* attachment's mime; defaults to `application/octet-stream` when omitted.
|
|
444
|
+
*/
|
|
445
|
+
output_mime?: unknown;
|
|
446
|
+
/**
|
|
447
|
+
* MIME the skill expects as a file input. Only valid in mode 'dynamic-script'
|
|
448
|
+
* (the only mode that receives a file via `ELISYM_INPUT_FILE`). Discovery hint
|
|
449
|
+
* only - the runtime still content-sniffs the actual file and does not enforce
|
|
450
|
+
* this. Convention: `*` = any file, `image/*` = any image, `image/png` =
|
|
451
|
+
* exact. Its presence signals "this capability needs a file input".
|
|
452
|
+
*/
|
|
453
|
+
input_mime?: unknown;
|
|
414
454
|
/**
|
|
415
455
|
* Optional per-skill rate limit. Applies to any skill mode. Snake-case
|
|
416
456
|
* keys here match the YAML frontmatter convention; parsed into camelCase
|
|
@@ -455,6 +495,14 @@ interface ParsedSkill {
|
|
|
455
495
|
scriptArgs: string[];
|
|
456
496
|
/** Undefined => caller uses `DEFAULT_SCRIPT_TIMEOUT_MS`. */
|
|
457
497
|
scriptTimeoutMs?: number;
|
|
498
|
+
/** MIME for a file result (mode 'dynamic-script' only). */
|
|
499
|
+
outputMime?: string;
|
|
500
|
+
/**
|
|
501
|
+
* MIME the skill expects as a file input (mode 'dynamic-script' only).
|
|
502
|
+
* Discovery hint only; not enforced at runtime. Presence signals the
|
|
503
|
+
* capability needs a file input (clients gate file-only flows on it).
|
|
504
|
+
*/
|
|
505
|
+
inputMime?: string;
|
|
458
506
|
/** Optional per-skill rate limit (any mode). */
|
|
459
507
|
rateLimit?: SkillRateLimit;
|
|
460
508
|
/**
|
package/dist/skills.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as Asset } from './assets-C-nzSYD4.js';
|
|
2
|
-
import { S as SkillRateLimit } from './types-
|
|
2
|
+
import { S as SkillRateLimit } from './types-Cdscy9kY.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Shared SKILL.md runtime types. A skill is a markdown document whose
|
|
@@ -12,10 +12,29 @@ interface SkillInput {
|
|
|
12
12
|
inputType: string;
|
|
13
13
|
tags: string[];
|
|
14
14
|
jobId: string;
|
|
15
|
+
/**
|
|
16
|
+
* Local path to a file input fetched out-of-band (P2P via iroh), when the job
|
|
17
|
+
* carried a file attachment. The runtime fetches it after payment and removes
|
|
18
|
+
* it after execution; the skill reads from disk rather than from `data`.
|
|
19
|
+
*/
|
|
20
|
+
filePath?: string;
|
|
15
21
|
}
|
|
16
22
|
interface SkillOutput {
|
|
17
23
|
data: string;
|
|
18
24
|
outputMime?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Local path to a file result. When set, the runtime seeds the file via iroh
|
|
27
|
+
* and the customer fetches it out-of-band; `data` carries any text note (or '').
|
|
28
|
+
* `outputMime` is reused as the attachment's mime.
|
|
29
|
+
*/
|
|
30
|
+
filePath?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Releases the resources backing `filePath` (e.g. a temp dir). The runtime
|
|
33
|
+
* calls it once it has seeded the file - or failed to - since seeding happens
|
|
34
|
+
* after `execute()` returns and the producer cannot release the file itself.
|
|
35
|
+
* Mirrors the input-side cleanup callback in the runtime's `resolveInputFile`.
|
|
36
|
+
*/
|
|
37
|
+
cleanup?: () => Promise<void>;
|
|
19
38
|
}
|
|
20
39
|
/**
|
|
21
40
|
* Optional per-skill LLM override declared in SKILL.md frontmatter.
|
|
@@ -342,6 +361,12 @@ interface DynamicScriptSkillParams {
|
|
|
342
361
|
* itself reads the key from its environment.
|
|
343
362
|
*/
|
|
344
363
|
llmOverride?: SkillLlmOverride;
|
|
364
|
+
/**
|
|
365
|
+
* MIME type the script declares for a file result (SKILL.md `output_mime`).
|
|
366
|
+
* Used only when the script writes a file to `ELISYM_OUTPUT_FILE`; becomes the
|
|
367
|
+
* iroh attachment's mime. Defaults to `application/octet-stream`.
|
|
368
|
+
*/
|
|
369
|
+
outputMime?: string;
|
|
345
370
|
}
|
|
346
371
|
/**
|
|
347
372
|
* Pipes the user's job input to the script's stdin and returns its
|
|
@@ -363,6 +388,7 @@ declare class DynamicScriptSkill implements Skill {
|
|
|
363
388
|
private scriptArgs;
|
|
364
389
|
private scriptTimeoutMs?;
|
|
365
390
|
private scriptEnv?;
|
|
391
|
+
private outputMime?;
|
|
366
392
|
constructor(params: DynamicScriptSkillParams);
|
|
367
393
|
execute(input: SkillInput, ctx: SkillContext): Promise<SkillOutput>;
|
|
368
394
|
}
|
|
@@ -411,6 +437,20 @@ interface SkillFrontmatter {
|
|
|
411
437
|
script_args?: unknown;
|
|
412
438
|
/** Optional override of `DEFAULT_SCRIPT_TIMEOUT_MS`. */
|
|
413
439
|
script_timeout_ms?: unknown;
|
|
440
|
+
/**
|
|
441
|
+
* MIME type for a file result. Only valid in mode 'dynamic-script' (the only
|
|
442
|
+
* mode that can emit a file via `ELISYM_OUTPUT_FILE`). Becomes the iroh
|
|
443
|
+
* attachment's mime; defaults to `application/octet-stream` when omitted.
|
|
444
|
+
*/
|
|
445
|
+
output_mime?: unknown;
|
|
446
|
+
/**
|
|
447
|
+
* MIME the skill expects as a file input. Only valid in mode 'dynamic-script'
|
|
448
|
+
* (the only mode that receives a file via `ELISYM_INPUT_FILE`). Discovery hint
|
|
449
|
+
* only - the runtime still content-sniffs the actual file and does not enforce
|
|
450
|
+
* this. Convention: `*` = any file, `image/*` = any image, `image/png` =
|
|
451
|
+
* exact. Its presence signals "this capability needs a file input".
|
|
452
|
+
*/
|
|
453
|
+
input_mime?: unknown;
|
|
414
454
|
/**
|
|
415
455
|
* Optional per-skill rate limit. Applies to any skill mode. Snake-case
|
|
416
456
|
* keys here match the YAML frontmatter convention; parsed into camelCase
|
|
@@ -455,6 +495,14 @@ interface ParsedSkill {
|
|
|
455
495
|
scriptArgs: string[];
|
|
456
496
|
/** Undefined => caller uses `DEFAULT_SCRIPT_TIMEOUT_MS`. */
|
|
457
497
|
scriptTimeoutMs?: number;
|
|
498
|
+
/** MIME for a file result (mode 'dynamic-script' only). */
|
|
499
|
+
outputMime?: string;
|
|
500
|
+
/**
|
|
501
|
+
* MIME the skill expects as a file input (mode 'dynamic-script' only).
|
|
502
|
+
* Discovery hint only; not enforced at runtime. Presence signals the
|
|
503
|
+
* capability needs a file input (clients gate file-only flows on it).
|
|
504
|
+
*/
|
|
505
|
+
inputMime?: string;
|
|
458
506
|
/** Optional per-skill rate limit (any mode). */
|
|
459
507
|
rateLimit?: SkillRateLimit;
|
|
460
508
|
/**
|
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
|
|
3
|
+
import { readFile, mkdtemp, stat, rm } from 'node:fs/promises';
|
|
4
|
+
import { dirname, join, resolve, relative, sep } from 'node:path';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
5
6
|
import { readdirSync, statSync, readFileSync } from 'node:fs';
|
|
6
7
|
import YAML from 'yaml';
|
|
7
8
|
import Decimal from 'decimal.js-light';
|
|
@@ -56,6 +57,14 @@ function runScript(cmd, args, opts) {
|
|
|
56
57
|
}
|
|
57
58
|
});
|
|
58
59
|
}
|
|
60
|
+
var SECRET_ENV_VARS = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY"];
|
|
61
|
+
function scopedToolEnv() {
|
|
62
|
+
const env = { ...process.env };
|
|
63
|
+
for (const key of SECRET_ENV_VARS) {
|
|
64
|
+
delete env[key];
|
|
65
|
+
}
|
|
66
|
+
return env;
|
|
67
|
+
}
|
|
59
68
|
var ScriptSkill = class {
|
|
60
69
|
name;
|
|
61
70
|
description;
|
|
@@ -177,13 +186,21 @@ var ScriptSkill = class {
|
|
|
177
186
|
if (value === void 0) {
|
|
178
187
|
continue;
|
|
179
188
|
}
|
|
189
|
+
const stringValue = String(value);
|
|
190
|
+
if (stringValue.startsWith("-")) {
|
|
191
|
+
return `Error: tool "${toolDef.name}" argument "${param.name}" must not begin with "-".`;
|
|
192
|
+
}
|
|
180
193
|
if (param.required && index === 0) {
|
|
181
|
-
args.push(
|
|
194
|
+
args.push(stringValue);
|
|
182
195
|
} else {
|
|
183
|
-
args.push(`--${param.name}`,
|
|
196
|
+
args.push(`--${param.name}`, stringValue);
|
|
184
197
|
}
|
|
185
198
|
}
|
|
186
|
-
const result = await runScript(cmd, args, {
|
|
199
|
+
const result = await runScript(cmd, args, {
|
|
200
|
+
cwd: this.skillDir,
|
|
201
|
+
signal,
|
|
202
|
+
env: scopedToolEnv()
|
|
203
|
+
});
|
|
187
204
|
if (result.spawnError) {
|
|
188
205
|
return `Error: ${result.spawnError.message}`;
|
|
189
206
|
}
|
|
@@ -246,6 +263,16 @@ var ScriptBillingExhaustedError = class extends Error {
|
|
|
246
263
|
this.stderr = stderr;
|
|
247
264
|
}
|
|
248
265
|
};
|
|
266
|
+
var ScriptExecutionError = class extends Error {
|
|
267
|
+
exitCode;
|
|
268
|
+
detail;
|
|
269
|
+
constructor(exitCode, detail, summary) {
|
|
270
|
+
super(summary ?? `script failed (exit ${exitCode ?? "unknown"})`);
|
|
271
|
+
this.name = "ScriptExecutionError";
|
|
272
|
+
this.exitCode = exitCode;
|
|
273
|
+
this.detail = detail;
|
|
274
|
+
}
|
|
275
|
+
};
|
|
249
276
|
|
|
250
277
|
// src/skills/staticScriptSkill.ts
|
|
251
278
|
var StaticScriptSkill = class {
|
|
@@ -284,19 +311,23 @@ var StaticScriptSkill = class {
|
|
|
284
311
|
env: this.scriptEnv
|
|
285
312
|
});
|
|
286
313
|
if (result.spawnError) {
|
|
287
|
-
throw new
|
|
314
|
+
throw new ScriptExecutionError(
|
|
315
|
+
null,
|
|
316
|
+
result.spawnError.message,
|
|
317
|
+
"script could not be started"
|
|
318
|
+
);
|
|
288
319
|
}
|
|
289
320
|
if (result.code === SCRIPT_EXIT_BILLING_EXHAUSTED) {
|
|
290
321
|
throw new ScriptBillingExhaustedError(result.code, result.stdout, result.stderr);
|
|
291
322
|
}
|
|
292
323
|
if (result.code !== 0) {
|
|
293
324
|
const detail = result.stderr.trim() || result.stdout.trim() || "(no output)";
|
|
294
|
-
throw new
|
|
325
|
+
throw new ScriptExecutionError(result.code, detail);
|
|
295
326
|
}
|
|
296
327
|
const output = result.stdout.trim();
|
|
297
328
|
if (output === "") {
|
|
298
329
|
const detail = result.stderr.trim() || "(no stderr)";
|
|
299
|
-
throw new
|
|
330
|
+
throw new ScriptExecutionError(result.code, detail, "script produced empty output");
|
|
300
331
|
}
|
|
301
332
|
return { data: output };
|
|
302
333
|
}
|
|
@@ -315,6 +346,7 @@ var DynamicScriptSkill = class {
|
|
|
315
346
|
scriptArgs;
|
|
316
347
|
scriptTimeoutMs;
|
|
317
348
|
scriptEnv;
|
|
349
|
+
outputMime;
|
|
318
350
|
constructor(params) {
|
|
319
351
|
this.name = params.name;
|
|
320
352
|
this.description = params.description;
|
|
@@ -328,31 +360,65 @@ var DynamicScriptSkill = class {
|
|
|
328
360
|
this.scriptArgs = params.scriptArgs;
|
|
329
361
|
this.scriptTimeoutMs = params.scriptTimeoutMs;
|
|
330
362
|
this.scriptEnv = params.scriptEnv;
|
|
363
|
+
this.outputMime = params.outputMime;
|
|
331
364
|
}
|
|
332
365
|
async execute(input, ctx) {
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
throw new Error(`script spawn failed: ${result.spawnError.message}`);
|
|
366
|
+
const outDir = await mkdtemp(join(tmpdir(), "elisym-skill-out-"));
|
|
367
|
+
const outputFile = join(outDir, "output");
|
|
368
|
+
const env = {
|
|
369
|
+
...this.scriptEnv ?? process.env,
|
|
370
|
+
ELISYM_OUTPUT_FILE: outputFile
|
|
371
|
+
};
|
|
372
|
+
if (input.filePath !== void 0) {
|
|
373
|
+
env.ELISYM_INPUT_FILE = input.filePath;
|
|
342
374
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
375
|
+
let keepOutDir = false;
|
|
376
|
+
try {
|
|
377
|
+
const result = await runScript(this.scriptPath, this.scriptArgs, {
|
|
378
|
+
cwd: dirname(this.scriptPath),
|
|
379
|
+
stdin: input.data,
|
|
380
|
+
signal: ctx.signal,
|
|
381
|
+
timeoutMs: this.scriptTimeoutMs,
|
|
382
|
+
env
|
|
383
|
+
});
|
|
384
|
+
if (result.spawnError) {
|
|
385
|
+
throw new ScriptExecutionError(
|
|
386
|
+
null,
|
|
387
|
+
result.spawnError.message,
|
|
388
|
+
"script could not be started"
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
if (result.code === SCRIPT_EXIT_BILLING_EXHAUSTED) {
|
|
392
|
+
throw new ScriptBillingExhaustedError(result.code, result.stdout, result.stderr);
|
|
393
|
+
}
|
|
394
|
+
if (result.code !== 0) {
|
|
395
|
+
const detail = result.stderr.trim() || result.stdout.trim() || "(no output)";
|
|
396
|
+
throw new ScriptExecutionError(result.code, detail);
|
|
397
|
+
}
|
|
398
|
+
const outputStat = await stat(outputFile).catch(() => null);
|
|
399
|
+
if (outputStat !== null && outputStat.isFile() && outputStat.size > 0) {
|
|
400
|
+
keepOutDir = true;
|
|
401
|
+
return {
|
|
402
|
+
data: result.stdout.trim(),
|
|
403
|
+
filePath: outputFile,
|
|
404
|
+
outputMime: this.outputMime ?? "application/octet-stream",
|
|
405
|
+
cleanup: async () => {
|
|
406
|
+
await rm(outDir, { recursive: true, force: true });
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
const output = result.stdout.trim();
|
|
411
|
+
if (output === "") {
|
|
412
|
+
const detail = result.stderr.trim() || "(no stderr)";
|
|
413
|
+
throw new ScriptExecutionError(result.code, detail, "script produced empty output");
|
|
414
|
+
}
|
|
415
|
+
return { data: output };
|
|
416
|
+
} finally {
|
|
417
|
+
if (!keepOutDir) {
|
|
418
|
+
await rm(outDir, { recursive: true, force: true }).catch(() => {
|
|
419
|
+
});
|
|
420
|
+
}
|
|
354
421
|
}
|
|
355
|
-
return { data: output };
|
|
356
422
|
}
|
|
357
423
|
};
|
|
358
424
|
function resolveInsidePath(rootDir, value) {
|
|
@@ -364,13 +430,13 @@ function resolveInsidePath(rootDir, value) {
|
|
|
364
430
|
}
|
|
365
431
|
return candidate;
|
|
366
432
|
}
|
|
367
|
-
var LAMPORTS_PER_SOL = 1e9;
|
|
368
433
|
var LIMITS = {
|
|
369
434
|
// Upper bound for execution budgets (`max_execution_secs` / `execution_timeout_secs`).
|
|
370
435
|
// Distinct from MAX_TIMEOUT_SECS (the result-wait cap): execution budgets may be
|
|
371
436
|
// hours, so this exists only to keep `secs * 1000` within Node's setTimeout limit
|
|
372
437
|
// (2_147_483_647 ms) - a larger value overflows and fires the timer immediately.
|
|
373
438
|
MAX_EXECUTION_SECS: 2147483};
|
|
439
|
+
new TextEncoder();
|
|
374
440
|
var NATIVE_SOL = {
|
|
375
441
|
chain: "solana",
|
|
376
442
|
token: "sol",
|
|
@@ -447,11 +513,15 @@ var VALID_MODES = [
|
|
|
447
513
|
"dynamic-script"
|
|
448
514
|
];
|
|
449
515
|
function solToLamports(sol) {
|
|
450
|
-
const
|
|
451
|
-
if (
|
|
516
|
+
const asString = (typeof sol === "string" ? sol : String(sol)).trim();
|
|
517
|
+
if (/^0+(?:\.0+)?$/.test(asString)) {
|
|
518
|
+
return 0n;
|
|
519
|
+
}
|
|
520
|
+
try {
|
|
521
|
+
return parseAssetAmount(NATIVE_SOL, asString);
|
|
522
|
+
} catch {
|
|
452
523
|
throw new Error(`Invalid SOL amount: ${sol}`);
|
|
453
524
|
}
|
|
454
|
-
return BigInt(Math.round(asNumber * LAMPORTS_PER_SOL));
|
|
455
525
|
}
|
|
456
526
|
function resolveSkillAsset(skillName, token, mint) {
|
|
457
527
|
if (token === void 0 || token === null) {
|
|
@@ -664,6 +734,34 @@ function validateScriptTimeoutMs(skillName, raw) {
|
|
|
664
734
|
}
|
|
665
735
|
return raw;
|
|
666
736
|
}
|
|
737
|
+
function validateOutputMime(skillName, raw) {
|
|
738
|
+
if (raw === void 0 || raw === null) {
|
|
739
|
+
return void 0;
|
|
740
|
+
}
|
|
741
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
742
|
+
throw new Error(
|
|
743
|
+
`SKILL.md "${skillName}": "output_mime" must be a non-empty string (e.g. "image/png")`
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
if (raw.length > 255) {
|
|
747
|
+
throw new Error(`SKILL.md "${skillName}": "output_mime" too long (max 255 chars)`);
|
|
748
|
+
}
|
|
749
|
+
return raw;
|
|
750
|
+
}
|
|
751
|
+
function validateInputMime(skillName, raw) {
|
|
752
|
+
if (raw === void 0 || raw === null) {
|
|
753
|
+
return void 0;
|
|
754
|
+
}
|
|
755
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
756
|
+
throw new Error(
|
|
757
|
+
`SKILL.md "${skillName}": "input_mime" must be a non-empty string (e.g. "image/png" or "*")`
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
if (raw.length > 255) {
|
|
761
|
+
throw new Error(`SKILL.md "${skillName}": "input_mime" too long (max 255 chars)`);
|
|
762
|
+
}
|
|
763
|
+
return raw;
|
|
764
|
+
}
|
|
667
765
|
function validateMaxExecutionSecs(skillName, raw) {
|
|
668
766
|
if (raw === void 0 || raw === null) {
|
|
669
767
|
return void 0;
|
|
@@ -715,7 +813,7 @@ function validateSkillFrontmatter(frontmatter, systemPrompt, options = {}) {
|
|
|
715
813
|
}
|
|
716
814
|
const priceString = typeof priceRaw === "number" ? String(priceRaw) : priceRaw;
|
|
717
815
|
if (asset === NATIVE_SOL) {
|
|
718
|
-
priceSubunits = solToLamports(
|
|
816
|
+
priceSubunits = solToLamports(priceString);
|
|
719
817
|
} else {
|
|
720
818
|
try {
|
|
721
819
|
priceSubunits = parseAssetAmount(asset, priceString);
|
|
@@ -764,6 +862,8 @@ function validateSkillFrontmatter(frontmatter, systemPrompt, options = {}) {
|
|
|
764
862
|
let script;
|
|
765
863
|
let scriptArgs = [];
|
|
766
864
|
let scriptTimeoutMs;
|
|
865
|
+
let outputMime;
|
|
866
|
+
let inputMime;
|
|
767
867
|
if (mode === "static-file") {
|
|
768
868
|
if (typeof frontmatter.output_file !== "string" || frontmatter.output_file.length === 0) {
|
|
769
869
|
throw new Error(
|
|
@@ -775,6 +875,16 @@ function validateSkillFrontmatter(frontmatter, systemPrompt, options = {}) {
|
|
|
775
875
|
`SKILL.md "${frontmatter.name}": "script" is not valid in mode 'static-file'`
|
|
776
876
|
);
|
|
777
877
|
}
|
|
878
|
+
if (frontmatter.output_mime !== void 0) {
|
|
879
|
+
throw new Error(
|
|
880
|
+
`SKILL.md "${frontmatter.name}": "output_mime" is only valid in mode 'dynamic-script'`
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
if (frontmatter.input_mime !== void 0) {
|
|
884
|
+
throw new Error(
|
|
885
|
+
`SKILL.md "${frontmatter.name}": "input_mime" is only valid in mode 'dynamic-script'`
|
|
886
|
+
);
|
|
887
|
+
}
|
|
778
888
|
outputFile = frontmatter.output_file;
|
|
779
889
|
} else if (mode === "static-script" || mode === "dynamic-script") {
|
|
780
890
|
if (typeof frontmatter.script !== "string" || frontmatter.script.length === 0) {
|
|
@@ -788,6 +898,21 @@ function validateSkillFrontmatter(frontmatter, systemPrompt, options = {}) {
|
|
|
788
898
|
script = frontmatter.script;
|
|
789
899
|
scriptArgs = validateScriptArgs(frontmatter.name, frontmatter.script_args);
|
|
790
900
|
scriptTimeoutMs = validateScriptTimeoutMs(frontmatter.name, frontmatter.script_timeout_ms);
|
|
901
|
+
if (mode === "dynamic-script") {
|
|
902
|
+
outputMime = validateOutputMime(frontmatter.name, frontmatter.output_mime);
|
|
903
|
+
inputMime = validateInputMime(frontmatter.name, frontmatter.input_mime);
|
|
904
|
+
} else {
|
|
905
|
+
if (frontmatter.output_mime !== void 0) {
|
|
906
|
+
throw new Error(
|
|
907
|
+
`SKILL.md "${frontmatter.name}": "output_mime" is only valid in mode 'dynamic-script'`
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
if (frontmatter.input_mime !== void 0) {
|
|
911
|
+
throw new Error(
|
|
912
|
+
`SKILL.md "${frontmatter.name}": "input_mime" is only valid in mode 'dynamic-script'`
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
791
916
|
} else {
|
|
792
917
|
if (frontmatter.output_file !== void 0) {
|
|
793
918
|
throw new Error(
|
|
@@ -809,6 +934,16 @@ function validateSkillFrontmatter(frontmatter, systemPrompt, options = {}) {
|
|
|
809
934
|
`SKILL.md "${frontmatter.name}": "script_timeout_ms" is only valid in script modes`
|
|
810
935
|
);
|
|
811
936
|
}
|
|
937
|
+
if (frontmatter.output_mime !== void 0) {
|
|
938
|
+
throw new Error(
|
|
939
|
+
`SKILL.md "${frontmatter.name}": "output_mime" is only valid in mode 'dynamic-script'`
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
if (frontmatter.input_mime !== void 0) {
|
|
943
|
+
throw new Error(
|
|
944
|
+
`SKILL.md "${frontmatter.name}": "input_mime" is only valid in mode 'dynamic-script'`
|
|
945
|
+
);
|
|
946
|
+
}
|
|
812
947
|
}
|
|
813
948
|
const image = typeof frontmatter.image === "string" ? frontmatter.image : void 0;
|
|
814
949
|
const imageFile = typeof frontmatter.image_file === "string" ? frontmatter.image_file : void 0;
|
|
@@ -835,11 +970,21 @@ function validateSkillFrontmatter(frontmatter, systemPrompt, options = {}) {
|
|
|
835
970
|
script,
|
|
836
971
|
scriptArgs,
|
|
837
972
|
scriptTimeoutMs,
|
|
973
|
+
outputMime,
|
|
974
|
+
inputMime,
|
|
838
975
|
rateLimit,
|
|
839
976
|
executionTimeoutSecs
|
|
840
977
|
};
|
|
841
978
|
}
|
|
842
979
|
function buildSkillFromParsed(parsed, skillDir, logger) {
|
|
980
|
+
let imageFile = parsed.imageFile;
|
|
981
|
+
if (imageFile !== void 0 && resolveInsidePath(skillDir, imageFile) === null) {
|
|
982
|
+
logger.warn?.(
|
|
983
|
+
{ skill: parsed.name, imageFile },
|
|
984
|
+
'SKILL.md "image_file" escapes the skill directory; ignoring it'
|
|
985
|
+
);
|
|
986
|
+
imageFile = void 0;
|
|
987
|
+
}
|
|
843
988
|
switch (parsed.mode) {
|
|
844
989
|
case "llm":
|
|
845
990
|
return new ScriptSkill({
|
|
@@ -854,7 +999,7 @@ function buildSkillFromParsed(parsed, skillDir, logger) {
|
|
|
854
999
|
maxToolRounds: parsed.maxToolRounds,
|
|
855
1000
|
llmOverride: parsed.llmOverride,
|
|
856
1001
|
image: parsed.image,
|
|
857
|
-
imageFile
|
|
1002
|
+
imageFile,
|
|
858
1003
|
logger
|
|
859
1004
|
});
|
|
860
1005
|
case "static-file": {
|
|
@@ -877,7 +1022,7 @@ function buildSkillFromParsed(parsed, skillDir, logger) {
|
|
|
877
1022
|
asset: parsed.asset,
|
|
878
1023
|
outputFilePath,
|
|
879
1024
|
image: parsed.image,
|
|
880
|
-
imageFile
|
|
1025
|
+
imageFile,
|
|
881
1026
|
llmOverride: parsed.llmOverride
|
|
882
1027
|
});
|
|
883
1028
|
}
|
|
@@ -892,8 +1037,7 @@ function buildSkillFromParsed(parsed, skillDir, logger) {
|
|
|
892
1037
|
if (!scriptPath) {
|
|
893
1038
|
throw new Error(`SKILL.md "${parsed.name}": "script" must stay inside the skill directory`);
|
|
894
1039
|
}
|
|
895
|
-
const
|
|
896
|
-
return new Ctor({
|
|
1040
|
+
const scriptParams = {
|
|
897
1041
|
name: parsed.name,
|
|
898
1042
|
description: parsed.description,
|
|
899
1043
|
capabilities: parsed.capabilities,
|
|
@@ -903,9 +1047,10 @@ function buildSkillFromParsed(parsed, skillDir, logger) {
|
|
|
903
1047
|
scriptArgs: parsed.scriptArgs,
|
|
904
1048
|
scriptTimeoutMs: parsed.scriptTimeoutMs ?? DEFAULT_SCRIPT_TIMEOUT_MS,
|
|
905
1049
|
image: parsed.image,
|
|
906
|
-
imageFile
|
|
1050
|
+
imageFile,
|
|
907
1051
|
llmOverride: parsed.llmOverride
|
|
908
|
-
}
|
|
1052
|
+
};
|
|
1053
|
+
return parsed.mode === "dynamic-script" ? new DynamicScriptSkill({ ...scriptParams, outputMime: parsed.outputMime }) : new StaticScriptSkill(scriptParams);
|
|
909
1054
|
}
|
|
910
1055
|
}
|
|
911
1056
|
}
|